diff --git a/PyMiner.spec b/PyMiner.spec deleted file mode 100644 index 3f704c3530dd64da319a886efb8975d791e503db..0000000000000000000000000000000000000000 --- a/PyMiner.spec +++ /dev/null @@ -1,97 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- -import sys -import os - - -sys.setrecursionlimit(5000) -block_cipher = None -SETUP_DIR = os.getcwd() -files = ['app2.py'] -pathex = os.getcwd() -datas = [] - - -def get_file(root, suffix=''): - files = os.listdir(root) - result = [] - # prefix = set() - for i in range(len(files)): - path = os.path.join(root, files[i]) - if os.path.isdir(path): - result.extend(get_file(path, suffix)) - if os.path.isfile(path) and path.endswith(suffix): - if suffix == '.py' and 'app2.py' in path: - pass - else: - result.append(path) - # prefix.add('.' + path.split('.')[-1]) - return result - - -def get_suffix(): - files = get_file(os.getcwd()) - suffix = set() - for file in files: - suffix.add('.' + file.split('.')[-1]) - suffix = list(suffix) - - for sf in suffix: - if '/' in sf: - suffix.remove(sf) - rev = ['.spec', '.gitignore', '.ui', '.md', '.txt', '.py'] - - for i in rev: - if i in suffix: - suffix.remove(i) - return suffix - - -def get_datas(): - datas = [] - suffix = get_suffix() - root = os.getcwd() - for sf in suffix: - files = get_file(root, suffix=sf) - for file in files: - abs_file = os.path.split(file)[-1] - datas.append((SETUP_DIR + file.replace(SETUP_DIR, ''), abs_file)) - return datas - - -files.extend(get_file(pathex, '.py')) -datas.extend(get_datas()) - -a = Analysis(files, - pathex=pathex, - binaries=[], - datas=datas, - hiddenimports=[], - hookspath=[], - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False) - - -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) -exe = EXE(pyz, - a.scripts, - [], - exclude_binaries=True, - name='PyMiner', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=False , icon='logo.ico') -coll = COLLECT(exe, - a.binaries, - a.zipfiles, - a.datas, - strip=False, - upx=True, - upx_exclude=[], - name='PyMiner') diff --git a/README.md b/README.md index 6649fb8131e24a78ed357d10b503018cb43485b7..bde14063c7d5cd4b030d4addb0a4be0c9d1d8f1c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ PyMiner已生成API文档,[PyMiner API](http://py2cn.gitee.io/pyminer/)。敬 1. 下载项目源码 2. 安装python并打开命令行工具,使用 pip install -r requirements.txt 导入python包,如果你的python依赖包下载太慢,建议使用:pip install -i https://mirrors.cloud.tencent.com/pypi/simple -r requirements.txt -3. 调用python 执行目录下 app2.py,例如python安装在C盘根目录下,可以在cmd命令行中执行:C:\python\python.exe C:\PyMiner\app.py +3. 调用python 执行目录下 app2.py,例如python安装在C盘根目录下,可以在cmd命令行中执行:C:\python\python.exe C:\PyMiner\app2.py **注意,整个项目已经迁移至 pyminer2,请使用 app2.py 作为入口程序** @@ -51,11 +51,11 @@ PyMiner已生成API文档,[PyMiner API](http://py2cn.gitee.io/pyminer/)。敬 #### 预览 基本界面 -![avatar](readme_figures/app2.png) +![avatar](pyminer2/ui/source/screenshot/app2.png) 变量 -![avatar](readme_figures/app2-table.png) +![avatar](pyminer2/ui/source/screenshot/app2-table.png) 绘图 -![avatar](readme_figures/app2-plot.png) +![avatar](pyminer2/ui/source/screenshot/app2-plot.png) diff --git a/LICENSE b/docs/LICENSE.GPL3 similarity index 92% rename from LICENSE rename to docs/LICENSE.GPL3 index f288702d2fa16d3cdf0035b15a9fcbc552cd88e7..a8d78217a0e7946730f5b6e87aca500b204fe559 100644 --- a/LICENSE +++ b/docs/LICENSE.GPL3 @@ -1,7 +1,16 @@ +PyMiner is Copyright (c) 2002 - 2020 PyMiner Development Team + +You may use, distribute and copy PyMiner under the terms of the GNU +General Public License as published by the Free Software Foundation, +either version 3 of the License, which is shown below, or (at your +option) any later version. + +------------------------------------------------------------------------- + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -619,56 +628,3 @@ Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cbb9eddb1bb1b4f366623044af8e4830919..0000000000000000000000000000000000000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/THANKS b/docs/THANKS new file mode 100644 index 0000000000000000000000000000000000000000..639e9769e389eb7ccfae78b751cd0c2f1d346a80 --- /dev/null +++ b/docs/THANKS @@ -0,0 +1,17 @@ +THANKS +------ + +Irony 为此项目的编辑器和控制台功能提供了支持 + +侯展意为此项目的菜单,工作区间等核心功能提供了支持 + +郑君为此项目的数据服务器等核心功能提供了支持 + +冰中的火为此项目的插件管理功能提供了支持 + +慢慢来别着急 为此项目的绘图功能提供了支持 + +...还有很多人,也有很大贡献,我为他们感到骄傲!谢谢你们为国产行业软件-数据处理软件做出的巨大贡献! + +Thanks, +Lixianglong diff --git a/docs/_build/doctrees/dts/app2.doctree b/docs/_build/doctrees/dts/app2.doctree deleted file mode 100644 index 2ba7f643f264a264e174890c372a673d9ca9d1e9..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/app2.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/modules.doctree b/docs/_build/doctrees/dts/modules.doctree deleted file mode 100644 index ffb0ae265c87e0cda496e4fd05eef5fca3c9366c..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/modules.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pmgwidgets.doctree b/docs/_build/doctrees/dts/pmgwidgets.doctree deleted file mode 100644 index 75c39efe178d2676a405a58e2311d1185d9c8ff7..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pmgwidgets.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pmgwidgets.normal.doctree b/docs/_build/doctrees/dts/pmgwidgets.normal.doctree deleted file mode 100644 index cbd86bd5632a53f5bb49ce1c108d2046b430622b..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pmgwidgets.normal.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pmgwidgets.table.doctree b/docs/_build/doctrees/dts/pmgwidgets.table.doctree deleted file mode 100644 index 82e3212fca6032a77be53b9b834c97aae646f9dd..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pmgwidgets.table.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.doctree b/docs/_build/doctrees/dts/pyminer2.doctree deleted file mode 100644 index 4184e0040f5098af9ee24f72e53998e9c4a11fc6..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.doctree deleted file mode 100644 index 2c53a176e1310d6ba8d381b6c6898d941b19188c..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.extensionlib.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.extensionlib.doctree deleted file mode 100644 index 5ae3e46477c551e0d3e7aedecbf2e47ed25de059..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.extensionlib.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.extensions_manager.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.extensions_manager.doctree deleted file mode 100644 index 29b3841b494f8586da752092b1d90b248e5da754..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.extensions_manager.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.package_manager.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.package_manager.doctree deleted file mode 100644 index 11d573e355d0cde14a381fb4377838a1e2408a6c..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.package_manager.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.doctree deleted file mode 100644 index 351081b690b679271607754be4bba1fc71df853a..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.doctree deleted file mode 100644 index 6d186d496aeda1ac426ee58ea9838f33573cd249..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension.doctree deleted file mode 100644 index 92f192f28dd55f7f8e8ded003f88b05018ba550f..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension2.doctree b/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension2.doctree deleted file mode 100644 index 000c69a43b2b1aa78926e9aba001fe1756c4f1ed..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.extensions.test_demo.extensions.test_extension2.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.base.doctree b/docs/_build/doctrees/dts/pyminer2.ui.base.doctree deleted file mode 100644 index aa72ae0897cffbfe2f332e187662c7afc46298e5..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.base.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.base.widgets.doctree b/docs/_build/doctrees/dts/pyminer2.ui.base.widgets.doctree deleted file mode 100644 index aa203b892963edc944dd68b60037a02a23cb38b8..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.base.widgets.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.common.doctree b/docs/_build/doctrees/dts/pyminer2.ui.common.doctree deleted file mode 100644 index 2d8f3c77df791abd78c3b7643be3db2d462e85c8..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.common.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.doctree b/docs/_build/doctrees/dts/pyminer2.ui.doctree deleted file mode 100644 index a37a62087b365edf010a5583aab35c66a463d705..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.basicwidgets.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.basicwidgets.doctree deleted file mode 100644 index ab9cd428e5686d28ea75ecb1f651d7f76b025232..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.basicwidgets.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.browser.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.browser.doctree deleted file mode 100644 index 66852d0c2acb6538a0bda2e7cb44e1a65bf333bb..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.browser.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.containers.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.containers.doctree deleted file mode 100644 index 158381f6b5e752b6b129bf37459ad7ebf68da651..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.containers.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.demos_and_tests.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.demos_and_tests.doctree deleted file mode 100644 index d96e151725f01f542cfca9a74357685f8773b6d7..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.demos_and_tests.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.doctree deleted file mode 100644 index ce0e948c527c36c3f660e3387f31e3c678a872fd..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.layouts.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.layouts.doctree deleted file mode 100644 index 13f5175025bc405fd0717aea430422e6e02def3f..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.layouts.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.sourcemgr.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.sourcemgr.doctree deleted file mode 100644 index d0e0e46a5c966a9177009d05b5f6ddb46c2af5e9..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.sourcemgr.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.table.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.table.doctree deleted file mode 100644 index 3188e9bc556e8c24bcb162bc0d91c02d79c47ce4..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.table.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.textctrls.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.textctrls.doctree deleted file mode 100644 index b208ac255bc5db293c118624453f9eeb1226a1ef..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.textctrls.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.toolbars.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.toolbars.doctree deleted file mode 100644 index 9a61e45e85976371c8ad3c3d8c7ae1c34e79aca1..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.toolbars.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.window.doctree b/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.window.doctree deleted file mode 100644 index e637747b0aef72d3860bf3b3dd902b7601c2a11a..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.generalwidgets.window.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.pmwidgets.doctree b/docs/_build/doctrees/dts/pyminer2.ui.pmwidgets.doctree deleted file mode 100644 index c9bd28d355716eab210ce86bcc8490485a9abd64..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.pmwidgets.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.source.doctree b/docs/_build/doctrees/dts/pyminer2.ui.source.doctree deleted file mode 100644 index 5720d4fb934ef0cef10493d12288b9b9fb7a2639..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.source.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.ui.source.qss.doctree b/docs/_build/doctrees/dts/pyminer2.ui.source.qss.doctree deleted file mode 100644 index 5c722670316a4d573fc701bbd8e2ad54820741dc..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.ui.source.qss.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.workspace.datamanager.doctree b/docs/_build/doctrees/dts/pyminer2.workspace.datamanager.doctree deleted file mode 100644 index 1354b02239b37cb5ec3f4dd2b9295add4188896e..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.workspace.datamanager.doctree and /dev/null differ diff --git a/docs/_build/doctrees/dts/pyminer2.workspace.doctree b/docs/_build/doctrees/dts/pyminer2.workspace.doctree deleted file mode 100644 index 8a96c2daf745af1e1ccb44ce8e49ae41127381ad..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/dts/pyminer2.workspace.doctree and /dev/null differ diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle deleted file mode 100644 index e86d32fddc35134c2bb5b09493a626c226b2e738..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/environment.pickle and /dev/null differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree deleted file mode 100644 index 48dfaf3e1258c0841807e44112b003fa2321212e..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/index.doctree and /dev/null differ diff --git a/docs/_build/doctrees/user/intro.doctree b/docs/_build/doctrees/user/intro.doctree deleted file mode 100644 index 2296dfdad517848d4491eef43eea68b83c9712ec..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/user/intro.doctree and /dev/null differ diff --git a/docs/_build/doctrees/user/joinus.doctree b/docs/_build/doctrees/user/joinus.doctree deleted file mode 100644 index 62a512b3278b204a8d0e6cf8de9b0742e63bc3bd..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/user/joinus.doctree and /dev/null differ diff --git a/docs/_build/doctrees/user/lib_ref.doctree b/docs/_build/doctrees/user/lib_ref.doctree deleted file mode 100644 index 2bc3156e231a3996754625759c6111b54282901e..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/user/lib_ref.doctree and /dev/null differ diff --git a/docs/_build/doctrees/user/tech.doctree b/docs/_build/doctrees/user/tech.doctree deleted file mode 100644 index d9b65b7af7c20f83de1e70bb4749b2d43955b7cd..0000000000000000000000000000000000000000 Binary files a/docs/_build/doctrees/user/tech.doctree and /dev/null differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo deleted file mode 100644 index e5b783d270f6642ba808393ca43515cdb30e0403..0000000000000000000000000000000000000000 --- a/docs/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 1081d76be17df49f60172e4adf499ffb -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_images/show1.jpg b/docs/_build/html/_images/show1.jpg deleted file mode 100644 index aa2cd6a19bc13a31d6c4b7195a48c9c785b3dc71..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_images/show1.jpg and /dev/null differ diff --git a/docs/_build/html/_images/show2.jpg b/docs/_build/html/_images/show2.jpg deleted file mode 100644 index 5ffd220623800a62c86c5a3afc7a14c50ce113e9..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_images/show2.jpg and /dev/null differ diff --git a/docs/_build/html/_images/show3.png b/docs/_build/html/_images/show3.png deleted file mode 100644 index ad1616915601f3154c69a0cc75cd52843a6ccc25..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_images/show3.png and /dev/null differ diff --git a/docs/_build/html/_sources/dts/app2.rst.txt b/docs/_build/html/_sources/dts/app2.rst.txt deleted file mode 100644 index 4ff5d31efab5c6488bbefd3a0c308ddbc18b3efd..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/app2.rst.txt +++ /dev/null @@ -1,7 +0,0 @@ -app2 module -=========== - -.. automodule:: app2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/modules.rst.txt b/docs/_build/html/_sources/dts/modules.rst.txt deleted file mode 100644 index 2db55fe5e3937c3d0f901ccf3deed5073eb8782c..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/modules.rst.txt +++ /dev/null @@ -1,9 +0,0 @@ -pyminer -======= - -.. toctree:: - :maxdepth: 4 - - app2 - pmgwidgets - pyminer2 diff --git a/docs/_build/html/_sources/dts/pmgwidgets.normal.rst.txt b/docs/_build/html/_sources/dts/pmgwidgets.normal.rst.txt deleted file mode 100644 index 41582119c96ebdb413613431855b65ea0dc0eaff..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pmgwidgets.normal.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pmgwidgets.normal package -========================= - -Submodules ----------- - -pmgwidgets.normal.value\_inputs module --------------------------------------- - -.. automodule:: pmgwidgets.normal.value_inputs - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.normal - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pmgwidgets.rst.txt b/docs/_build/html/_sources/dts/pmgwidgets.rst.txt deleted file mode 100644 index 2b71277a4e546f65ad0a212f4cc8c180bd4fa1cb..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pmgwidgets.rst.txt +++ /dev/null @@ -1,19 +0,0 @@ -pmgwidgets package -================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pmgwidgets.normal - pmgwidgets.table - -Module contents ---------------- - -.. automodule:: pmgwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pmgwidgets.table.rst.txt b/docs/_build/html/_sources/dts/pmgwidgets.table.rst.txt deleted file mode 100644 index 82988eff55f237eed64ba821a326be42ec3dc52c..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pmgwidgets.table.rst.txt +++ /dev/null @@ -1,29 +0,0 @@ -pmgwidgets.table package -======================== - -Submodules ----------- - -pmgwidgets.table.tableviews module ----------------------------------- - -.. automodule:: pmgwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pmgwidgets.table.tablewidgets module ------------------------------------- - -.. automodule:: pmgwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.table - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.extensionlib.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.extensionlib.rst.txt deleted file mode 100644 index bebe3e024d6add3160781ef4b234da8b905799ef..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.extensionlib.rst.txt +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.extensions.extensionlib package -======================================== - -Submodules ----------- - -pyminer2.extensions.extensionlib.baseext module ------------------------------------------------ - -.. automodule:: pyminer2.extensions.extensionlib.baseext - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.extension\_lib module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.extension_lib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.pmext module ---------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.pmext - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensionlib - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.extensions_manager.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.extensions_manager.rst.txt deleted file mode 100644 index 53f92b4ac15fdcaddbf9feccd2b30be2ac6ef0cf..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.extensions_manager.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.extensions\_manager package -=============================================== - -Submodules ----------- - -pyminer2.extensions.extensions\_manager.ExtensionLoader module --------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.ExtensionLoader - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.UIInserter module ---------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.UIInserter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.log module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.log - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.manager module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.manager - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensions_manager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.package_manager.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.package_manager.rst.txt deleted file mode 100644 index ecc8b09965408155b62a2091f350b03e69fab706..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.package_manager.rst.txt +++ /dev/null @@ -1,61 +0,0 @@ -pyminer2.extensions.package\_manager package -============================================ - -Submodules ----------- - -pyminer2.extensions.package\_manager.env\_manager module --------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.env_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_install module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_install - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_manager module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_remove module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_remove - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_setting module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_setting - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_update module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_update - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.package_manager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.rst.txt deleted file mode 100644 index 2eb1dc016f9cf75cca6f68daaa33f14614bd62e4..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.extensions package -=========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.extensionlib - pyminer2.extensions.extensions_manager - pyminer2.extensions.package_manager - pyminer2.extensions.test_demo - -Module contents ---------------- - -.. automodule:: pyminer2.extensions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.rst.txt deleted file mode 100644 index b3eb3e7d27299762835f8bc2ce14331f5a72f0f4..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.rst.txt +++ /dev/null @@ -1,19 +0,0 @@ -pyminer2.extensions.test\_demo.extensions package -================================================= - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions.test_extension - pyminer2.extensions.test_demo.extensions.test_extension2 - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst.txt deleted file mode 100644 index 1b636f70e730679b8893ec704eb7ccd33a911fff..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.test\_demo.extensions.test\_extension package -================================================================= - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension.entry module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.interface module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.menu module ---------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.subwindow module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst.txt deleted file mode 100644 index 3a25526b0ad3c5fdedb4d605fa4503c9f168e5d7..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.test\_demo.extensions.test\_extension2 package -================================================================== - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension2.entry module ------------------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.interface module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.menu module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.subwindow module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.rst.txt b/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.rst.txt deleted file mode 100644 index 6fe415622f2f8529feb54c491058b55629611db0..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.extensions.test_demo.rst.txt +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.extensions.test\_demo package -====================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensionlib module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensionlib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.mainform module ----------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.mainform - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.rst.txt b/docs/_build/html/_sources/dts/pyminer2.rst.txt deleted file mode 100644 index 5cbe121ddafd9725c5acb97b20e8ec64d2df4570..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.rst.txt +++ /dev/null @@ -1,39 +0,0 @@ -pyminer2 package -================ - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions - pyminer2.ui - pyminer2.workspace - -Submodules ----------- - -pyminer2.pmappmodern module ---------------------------- - -.. automodule:: pyminer2.pmappmodern - :members: - :undoc-members: - :show-inheritance: - -pyminer2.pmutil module ----------------------- - -.. automodule:: pyminer2.pmutil - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.base.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.base.rst.txt deleted file mode 100644 index fad413b3fce875c16742dd2e7abb5a8f0eece312..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.base.rst.txt +++ /dev/null @@ -1,61 +0,0 @@ -pyminer2.ui.base package -======================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base.widgets - -Submodules ----------- - -pyminer2.ui.base.aboutMe module -------------------------------- - -.. automodule:: pyminer2.ui.base.aboutMe - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.flow module ----------------------------- - -.. automodule:: pyminer2.ui.base.flow - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.mainForm module --------------------------------- - -.. automodule:: pyminer2.ui.base.mainForm - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.newItem module -------------------------------- - -.. automodule:: pyminer2.ui.base.newItem - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.option module ------------------------------- - -.. automodule:: pyminer2.ui.base.option - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.base.widgets.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.base.widgets.rst.txt deleted file mode 100644 index 16fb4b91ab324667562ec040a474b6818615803e..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.base.widgets.rst.txt +++ /dev/null @@ -1,93 +0,0 @@ -pyminer2.ui.base.widgets package -================================ - -Submodules ----------- - -pyminer2.ui.base.widgets.consolewidget module ---------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.consolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.controlpanel module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.controlpanel - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.flowwidget module ------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.flowwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.menu\_tool\_stat\_bars module ------------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.menu_tool_stat_bars - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.notificationwidget module --------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.notificationwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.reportwidget module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.reportwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.resources module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.resources - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.tablewidget module -------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.tablewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.texteditconsolewidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.texteditconsolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.treeviews module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.treeviews - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base.widgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.common.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.common.rst.txt deleted file mode 100644 index 28bbff7e257e686372f9c1db8c9afb8522405e37..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.common.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.common package -========================== - -Submodules ----------- - -pyminer2.ui.common.locale module --------------------------------- - -.. automodule:: pyminer2.ui.common.locale - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.openprocess module -------------------------------------- - -.. automodule:: pyminer2.ui.common.openprocess - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.platformutil module --------------------------------------- - -.. automodule:: pyminer2.ui.common.platformutil - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.test\_comm module ------------------------------------- - -.. automodule:: pyminer2.ui.common.test_comm - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.common - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.basicwidgets.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.basicwidgets.rst.txt deleted file mode 100644 index 6a74ea0302a17efd13d506a0fd1353ff1c6689fc..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.basicwidgets.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.generalwidgets.basicwidgets package -=============================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.basicwidgets.labels module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.labels - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.object module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.object - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module ------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.toolbutton module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.toolbutton - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.browser.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.browser.rst.txt deleted file mode 100644 index 49ae6ffc55ab51c6907926506495c2cff66d7d72..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.browser.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.browser package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.browser.browser module -------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser.browser - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.containers.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.containers.rst.txt deleted file mode 100644 index 98d7c387869969e634b340bea0b690ce87792132..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.containers.rst.txt +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.ui.generalwidgets.containers package -============================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.containers.PMTab module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.PMTab - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.flowarea module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.containers.flowarea - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.pmscrollarea module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.pmscrollarea - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst.txt deleted file mode 100644 index 019f849ed6a83f3f23bc7c0ab747542fa2a92f02..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.demos\_and\_tests package -==================================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.demos\_and\_tests.qmenu\_demo module ---------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.layouts.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.layouts.rst.txt deleted file mode 100644 index eb1919f243b8583e79f8ffa4c3ee94de91a8f1a2..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.layouts.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.layouts package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.layouts.flowlayout module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts.flowlayout - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.rst.txt deleted file mode 100644 index 0e8db3e1ec940a19d7300049a46d96ffe0a35185..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.rst.txt +++ /dev/null @@ -1,27 +0,0 @@ -pyminer2.ui.generalwidgets package -================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.generalwidgets.basicwidgets - pyminer2.ui.generalwidgets.browser - pyminer2.ui.generalwidgets.containers - pyminer2.ui.generalwidgets.demos_and_tests - pyminer2.ui.generalwidgets.layouts - pyminer2.ui.generalwidgets.sourcemgr - pyminer2.ui.generalwidgets.table - pyminer2.ui.generalwidgets.textctrls - pyminer2.ui.generalwidgets.toolbars - pyminer2.ui.generalwidgets.window - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.sourcemgr.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.sourcemgr.rst.txt deleted file mode 100644 index f2abea94f3bb41a0346a7af9eb084953256403d7..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.sourcemgr.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.sourcemgr package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.sourcemgr.iconutils module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr.iconutils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.table.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.table.rst.txt deleted file mode 100644 index 8e191e84acef2ce0ed1f4ab17a0c2eb902107af4..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.table.rst.txt +++ /dev/null @@ -1,29 +0,0 @@ -pyminer2.ui.generalwidgets.table package -======================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.table.tableviews module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.table.tablewidgets module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.table - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.textctrls.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.textctrls.rst.txt deleted file mode 100644 index 73ba688af6bae47d237cc1d071eff2b888cc55df..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.textctrls.rst.txt +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.ui.generalwidgets.textctrls package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.textctrls.highlighter module -------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.highlighter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textctrl module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textctrl - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module --------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.toolbars.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.toolbars.rst.txt deleted file mode 100644 index d1b0a959c9915f94c66301f23311f4d374354dbd..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.toolbars.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.toolbars package -=========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.toolbars.toolbar module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars.toolbar - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.window.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.window.rst.txt deleted file mode 100644 index c143a91890bb221d0942ff2fa79687c1307b3537..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.generalwidgets.window.rst.txt +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.generalwidgets.window package -========================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.window.applicationtest module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.applicationtest - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.mainwindow\_new module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.mainwindow_new - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmdockwidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmdockwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmmainwindow module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmmainwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.window - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.pmwidgets.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.pmwidgets.rst.txt deleted file mode 100644 index 843613ec32499c007fc5aecf23af21647bc9c16c..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.pmwidgets.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.pmwidgets package -============================= - -Submodules ----------- - -pyminer2.ui.pmwidgets.toplevel module -------------------------------------- - -.. automodule:: pyminer2.ui.pmwidgets.toplevel - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.pmwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.rst.txt deleted file mode 100644 index f16cf5c71335f5dc39f08850378c5214423605c1..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.rst.txt +++ /dev/null @@ -1,33 +0,0 @@ -pyminer2.ui package -=================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base - pyminer2.ui.common - pyminer2.ui.generalwidgets - pyminer2.ui.pmwidgets - pyminer2.ui.source - -Submodules ----------- - -pyminer2.ui.pyqtsource\_rc module ---------------------------------- - -.. automodule:: pyminer2.ui.pyqtsource_rc - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.source.qss.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.source.qss.rst.txt deleted file mode 100644 index 84a967853e65d3fc79a2786ecaa402ca8cec2b69..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.source.qss.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.source.qss package -============================== - -Submodules ----------- - -pyminer2.ui.source.qss.qss\_tools module ----------------------------------------- - -.. automodule:: pyminer2.ui.source.qss.qss_tools - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source.qss - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.ui.source.rst.txt b/docs/_build/html/_sources/dts/pyminer2.ui.source.rst.txt deleted file mode 100644 index 2293991a056e8b8a5bc95824c2de05f607826cec..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.ui.source.rst.txt +++ /dev/null @@ -1,18 +0,0 @@ -pyminer2.ui.source package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.source.qss - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.workspace.datamanager.rst.txt b/docs/_build/html/_sources/dts/pyminer2.workspace.datamanager.rst.txt deleted file mode 100644 index 3de07e48ce0a19d65b6991ae7af2ba3f1bf77c46..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.workspace.datamanager.rst.txt +++ /dev/null @@ -1,85 +0,0 @@ -pyminer2.workspace.datamanager package -====================================== - -Submodules ----------- - -pyminer2.workspace.datamanager.converter module ------------------------------------------------ - -.. automodule:: pyminer2.workspace.datamanager.converter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.datamanager module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.datamanager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.dataset module ---------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.dataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.exceptions module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.exceptions - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.historyset module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.historyset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.metadataset module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.metadataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.recyclebin module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.recyclebin - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.variable module ----------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.variable - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.varset module --------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.varset - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.workspace.datamanager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/dts/pyminer2.workspace.rst.txt b/docs/_build/html/_sources/dts/pyminer2.workspace.rst.txt deleted file mode 100644 index dc250a80fdfb6b5c99875721e52e2bc801d193b5..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/dts/pyminer2.workspace.rst.txt +++ /dev/null @@ -1,18 +0,0 @@ -pyminer2.workspace package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.workspace.datamanager - -Module contents ---------------- - -.. automodule:: pyminer2.workspace - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt deleted file mode 100644 index e19d343081199815e7fe945b4990ca824f49893e..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/index.rst.txt +++ /dev/null @@ -1,36 +0,0 @@ -.. PyMiner documentation master file, created by - sphinx-quickstart on Wed Sep 9 22:58:12 2020. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PyMiner's documentation! -=================================== -PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。 - -User Guide ----------- - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - user/intro - user/tech - user/joinus - -API Reference ------------------ - -.. toctree:: - :maxdepth: 30 - :caption: Contents: - - user/lib_ref.rst - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/_build/html/_sources/user/intro.rst.txt b/docs/_build/html/_sources/user/intro.rst.txt deleted file mode 100644 index 3004214f74e082db1327d40fa5650ff5c92ca604..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/user/intro.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -Introduction -============ - -Brief --------- -PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。官方网站:www.py2cn.com - -License -------- -本项目遵循GPL许可证。此外,对个人用户来说,本项目支持自由修改源码和使用,但是不支持任何未经授权许可的商用或其他盈利性行为,也不支持任何未经授权申请著作权的行为。如有违反以上许可,本项目管理团队有权进行否决。 许可解释权归属 PyMiner Development Team。 - -Cut --------- - -预览1(主界面) ->>>>>>>>>> - -.. image:: /image/show1.jpg - :scale: 40% - -预览2(表格显示) ->>>>>>>>>> - -.. image:: /image/show2.jpg - :scale: 40% - -预览3(编辑器) ->>>>>>>>>> - -.. image:: /image/show3.png - :scale: 40% \ No newline at end of file diff --git a/docs/_build/html/_sources/user/joinus.rst.txt b/docs/_build/html/_sources/user/joinus.rst.txt deleted file mode 100644 index 6b587c6b62571dd9f029e0aa2f79ca418567a0e4..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/user/joinus.rst.txt +++ /dev/null @@ -1,42 +0,0 @@ -Join Us -============ - -Preface ------- - -为了更便于推进项目,需要了解各位擅长的工作内容,请各位群友修改自己的备注为:方向+昵称,例如pyqt_tom_coffce - -Develop Group -------------- -目前开发组已经有pyqt、算法、仿真、插件、网站、c++、项目管理多个小分队,有意向在任意领域进行参与贡献的小伙伴请直接加入小分队QQ群! - -PyMiner开发者QQ总群:945391275 - -pyqt小分队:907932713 - -算法小分队:605160230 - -仿真小分队:915736652 - -插件小分队:689417488 - -C++小分队:205591506 - -网站小分队:1131420577 - -项目管理小分队:827058366 - -产品经理/需求分析师小分队:1026801187 - - -How to Contribute:: -------------- -要真正的参与项目,除了需要了解自身特长之外,还需要了解这个项目的基本情况。在Wiki的“ 项目说明 ”我们有对项目的背景做一些介绍,在“ 项目计划 ”中我们对当前我们正在做的事情以及下一步的项目计划做了概要性描述。 - -如果你是偏产品经理和需求分析师方面的,想要为项目做些贡献,我们希望你能对matlab多一些认识,毕竟我们的目标是进行matlab替代。在此基础上,希望你能帮助我们进行需求分解,将matlab的功能模块按照重要性、优先级进行细化分解,以便我们能够更专注于细节进行实现。 - -如果你是偏qt pyqt python 方向的,想要在PyMiner的界面UI或功能方面进行参与,我们也很希望你能真正的参与到项目的代码贡献当中。在这之前你可能还需要了解我们的代码结构(在wiki的“ 开发者指南 ”中我们会有相应介绍),编码规范(在wiki的“ 编程规范 ”中)。 - -如果你是仿真方向或对Sumlink有所研究,除了项目基础信息之外,你还需要了解项目的插件系统,目前在PyMiner中,更多功能将以插件的形式进行提供。而插件我们支持使用Python或c++等多种方式进行开发。 - -如果你是算法工程师,你将是这个项目的非常重要参与者,甚至可以说,我们的未来非常依赖你们的参与,而在PyMiner中,算法工程师的贡献,也将主要通过插件的形式进行完成,为此我们需要算法工程师和其他开发者齐心协力进行合作, 由算法进行后台计算并设计输入参数和输出形式,而pyqt开发者进行插件化改造实现 ,最终将算法以插件的形式对外提供。 \ No newline at end of file diff --git a/docs/_build/html/_sources/user/lib_ref.rst.txt b/docs/_build/html/_sources/user/lib_ref.rst.txt deleted file mode 100644 index 59e8072b91d223a735767bdc8dc16edeb400edbf..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/user/lib_ref.rst.txt +++ /dev/null @@ -1,1158 +0,0 @@ -API Reference -================= - - -app2 module -=========== - -.. automodule:: app2 - :members: - :undoc-members: - :show-inheritance: -pyminer -======= - -.. toctree:: - :maxdepth: 4 - - app2 - pmgwidgets - pyminer2 -pmgwidgets.normal package -========================= - -Submodules ----------- - -pmgwidgets.normal.value\_inputs module --------------------------------------- - -.. automodule:: pmgwidgets.normal.value_inputs - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.normal - :members: - :undoc-members: - :show-inheritance: -pmgwidgets package -================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pmgwidgets.normal - pmgwidgets.table - -Module contents ---------------- - -.. automodule:: pmgwidgets - :members: - :undoc-members: - :show-inheritance: -pmgwidgets.table package -======================== - -Submodules ----------- - -pmgwidgets.table.tableviews module ----------------------------------- - -.. automodule:: pmgwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pmgwidgets.table.tablewidgets module ------------------------------------- - -.. automodule:: pmgwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.table - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.extensionlib package -======================================== - -Submodules ----------- - -pyminer2.extensions.extensionlib.baseext module ------------------------------------------------ - -.. automodule:: pyminer2.extensions.extensionlib.baseext - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.extension\_lib module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.extension_lib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.pmext module ---------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.pmext - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensionlib - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.extensions\_manager package -=============================================== - -Submodules ----------- - -pyminer2.extensions.extensions\_manager.ExtensionLoader module --------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.ExtensionLoader - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.UIInserter module ---------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.UIInserter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.log module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.log - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.manager module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.manager - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensions_manager - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.package\_manager package -============================================ - -Submodules ----------- - -pyminer2.extensions.package\_manager.env\_manager module --------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.env_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_install module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_install - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_manager module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_remove module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_remove - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_setting module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_setting - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_update module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_update - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.package_manager - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions package -=========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.extensionlib - pyminer2.extensions.extensions_manager - pyminer2.extensions.package_manager - pyminer2.extensions.test_demo - -Module contents ---------------- - -.. automodule:: pyminer2.extensions - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions package -================================================= - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions.test_extension - pyminer2.extensions.test_demo.extensions.test_extension2 - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions.test\_extension2 package -================================================================== - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension2.entry module ------------------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.interface module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.menu module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.subwindow module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2 - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions.test\_extension package -================================================================= - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension.entry module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.interface module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.menu module ---------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.subwindow module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo package -====================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensionlib module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensionlib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.mainform module ----------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.mainform - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo - :members: - :undoc-members: - :show-inheritance: -pyminer2 package -================ - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions - pyminer2.ui - pyminer2.workspace - -Submodules ----------- - -pyminer2.pmappmodern module ---------------------------- - -.. automodule:: pyminer2.pmappmodern - :members: - :undoc-members: - :show-inheritance: - -pyminer2.pmutil module ----------------------- - -.. automodule:: pyminer2.pmutil - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2 - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.base package -======================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base.widgets - -Submodules ----------- - -pyminer2.ui.base.aboutMe module -------------------------------- - -.. automodule:: pyminer2.ui.base.aboutMe - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.flow module ----------------------------- - -.. automodule:: pyminer2.ui.base.flow - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.mainForm module --------------------------------- - -.. automodule:: pyminer2.ui.base.mainForm - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.newItem module -------------------------------- - -.. automodule:: pyminer2.ui.base.newItem - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.option module ------------------------------- - -.. automodule:: pyminer2.ui.base.option - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.base.widgets package -================================ - -Submodules ----------- - -pyminer2.ui.base.widgets.consolewidget module ---------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.consolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.controlpanel module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.controlpanel - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.flowwidget module ------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.flowwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.menu\_tool\_stat\_bars module ------------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.menu_tool_stat_bars - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.notificationwidget module --------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.notificationwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.reportwidget module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.reportwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.resources module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.resources - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.tablewidget module -------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.tablewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.texteditconsolewidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.texteditconsolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.treeviews module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.treeviews - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base.widgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.common package -========================== - -Submodules ----------- - -pyminer2.ui.common.locale module --------------------------------- - -.. automodule:: pyminer2.ui.common.locale - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.openprocess module -------------------------------------- - -.. automodule:: pyminer2.ui.common.openprocess - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.platformutil module --------------------------------------- - -.. automodule:: pyminer2.ui.common.platformutil - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.test\_comm module ------------------------------------- - -.. automodule:: pyminer2.ui.common.test_comm - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.common - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.basicwidgets package -=============================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.basicwidgets.labels module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.labels - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.object module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.object - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module ------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.toolbutton module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.toolbutton - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.browser package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.browser.browser module -------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser.browser - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.containers package -============================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.containers.PMTab module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.PMTab - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.flowarea module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.containers.flowarea - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.pmscrollarea module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.pmscrollarea - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.demos\_and\_tests package -==================================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.demos\_and\_tests.qmenu\_demo module ---------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.layouts package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.layouts.flowlayout module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts.flowlayout - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets package -================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.generalwidgets.basicwidgets - pyminer2.ui.generalwidgets.browser - pyminer2.ui.generalwidgets.containers - pyminer2.ui.generalwidgets.demos_and_tests - pyminer2.ui.generalwidgets.layouts - pyminer2.ui.generalwidgets.sourcemgr - pyminer2.ui.generalwidgets.table - pyminer2.ui.generalwidgets.textctrls - pyminer2.ui.generalwidgets.toolbars - pyminer2.ui.generalwidgets.window - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.sourcemgr package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.sourcemgr.iconutils module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr.iconutils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.table package -======================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.table.tableviews module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.table.tablewidgets module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.table - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.textctrls package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.textctrls.highlighter module -------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.highlighter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textctrl module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textctrl - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module --------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.toolbars package -=========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.toolbars.toolbar module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars.toolbar - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.window package -========================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.window.applicationtest module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.applicationtest - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.mainwindow\_new module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.mainwindow_new - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmdockwidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmdockwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmmainwindow module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmmainwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.window - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.pmwidgets package -============================= - -Submodules ----------- - -pyminer2.ui.pmwidgets.toplevel module -------------------------------------- - -.. automodule:: pyminer2.ui.pmwidgets.toplevel - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.pmwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui package -=================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base - pyminer2.ui.common - pyminer2.ui.generalwidgets - pyminer2.ui.pmwidgets - pyminer2.ui.source - -Submodules ----------- - -pyminer2.ui.pyqtsource\_rc module ---------------------------------- - -.. automodule:: pyminer2.ui.pyqtsource_rc - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.source.qss package -============================== - -Submodules ----------- - -pyminer2.ui.source.qss.qss\_tools module ----------------------------------------- - -.. automodule:: pyminer2.ui.source.qss.qss_tools - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source.qss - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.source package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.source.qss - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source - :members: - :undoc-members: - :show-inheritance: -pyminer2.workspace.datamanager package -====================================== - -Submodules ----------- - -pyminer2.workspace.datamanager.converter module ------------------------------------------------ - -.. automodule:: pyminer2.workspace.datamanager.converter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.datamanager module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.datamanager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.dataset module ---------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.dataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.exceptions module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.exceptions - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.historyset module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.historyset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.metadataset module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.metadataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.recyclebin module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.recyclebin - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.variable module ----------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.variable - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.varset module --------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.varset - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.workspace.datamanager - :members: - :undoc-members: - :show-inheritance: -pyminer2.workspace package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.workspace.datamanager - -Module contents ---------------- - -.. automodule:: pyminer2.workspace - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/user/tech.rst.txt b/docs/_build/html/_sources/user/tech.rst.txt deleted file mode 100644 index 7c895afe9fb9449620bbb24d1d2c04beb3b60837..0000000000000000000000000000000000000000 --- a/docs/_build/html/_sources/user/tech.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -Technology -============ - -Develop Environment -------- -PyMiner项目开发环境基于Windows 10 X64,使用Python3.8+PyQt5.15+Pycharm进行技术开发, 同时,此项目支持跨平台,这意味着即使是Linux、Mac也可以直接使用或开发此软件! - -Installation -------- - -下载项目源码 ->>>>>>>>>> - -安装python并打开命令行工具,使用 pip install -r requirements.txt 导入python包,如果你的python依赖包下载太慢,我建议使用:pip install -i https://mirrors.cloud.tencent.com/pypi/simple -r requirements.txt ->>>>>>>>>>>>>>>>>>> - -调用python 执行目录下pyminer.py,例如python安装在C盘根目录下,可以在cmd命令行中执行:C:\python\python.exe C:\PyMiner\pyminer.py ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -此外,你也可以使用pyinstaller进行编译后使用,编译语句:pyinstaller -i logo.ico -w pyminer.py ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \ No newline at end of file diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css deleted file mode 100644 index 24bc73e7f51edb00f73d5cf222632c875dce6657..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/basic.css +++ /dev/null @@ -1,855 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/_build/html/_static/css/badge_only.css b/docs/_build/html/_static/css/badge_only.css deleted file mode 100644 index e380325bc6e273d9142c2369883d2a4b2a069cf1..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/css/badge_only.css +++ /dev/null @@ -1 +0,0 @@ -.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff deleted file mode 100644 index 6cb60000181dbd348963953ac8ac54afb46c63d5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 deleted file mode 100644 index 7059e23142aae3d8bad6067fc734a6cffec779c9..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff deleted file mode 100644 index f815f63f99da80ad2be69e4021023ec2981eaea0..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 deleted file mode 100644 index f2c76e5bda18a9842e24cd60d8787257da215ca7..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot b/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca953f93e35eab4108bd414bc02ddcf3928..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg b/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e538b65548118279537a04eab2ec6ef0d..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf b/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1196aad98c2adf4378a7611dd713aa3..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b06eee3d0c0d54402a47ab2601b2862b..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60404b91e398a37200c4a77b645cfd9586..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff deleted file mode 100644 index 88ad05b9ff413055b4d4e89dd3eec1c193fa20c6..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 deleted file mode 100644 index c4e3d804b57b625b16a36d767bfca6bbf63d414e..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff b/docs/_build/html/_static/css/fonts/lato-bold.woff deleted file mode 100644 index c6dff51f063cc732fdb5fe786a8966de85f4ebec..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff2 b/docs/_build/html/_static/css/fonts/lato-bold.woff2 deleted file mode 100644 index bb195043cfc07fa52741c6144d7378b5ba8be4c5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff deleted file mode 100644 index 76114bc03362242c3325ecda6ce6d02bb737880f..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 deleted file mode 100644 index 3404f37e2e312757841abe20343588a7740768ca..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff b/docs/_build/html/_static/css/fonts/lato-normal.woff deleted file mode 100644 index ae1307ff5f4c48678621c240f8972d5a6e20b22c..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-normal.woff and /dev/null differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff2 b/docs/_build/html/_static/css/fonts/lato-normal.woff2 deleted file mode 100644 index 3bf9843328a6359b6bd06e50010319c63da0d717..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/css/fonts/lato-normal.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/css/theme.css b/docs/_build/html/_static/css/theme.css deleted file mode 100644 index 8cd4f101a91d864f52b340128fddc1e6b39cddbb..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/css/theme.css +++ /dev/null @@ -1,4 +0,0 @@ -html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li span.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li span.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li span.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li span.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li span.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p.caption .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.btn .wy-menu-vertical li span.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p.caption .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.nav .wy-menu-vertical li span.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p.caption .btn .headerlink,.rst-content p.caption .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li span.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol li,.rst-content ol.arabic li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content ol.arabic li p:last-child,.rst-content ol.arabic li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover span.toctree-expand,.wy-menu-vertical li.on a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp{user-select:none;pointer-events:none}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content .code-block-caption .headerlink:after,.rst-content .toctree-wrapper>p.caption .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"\f0c1";font-family:FontAwesome}.rst-content .code-block-caption:hover .headerlink:after,.rst-content .toctree-wrapper>p.caption:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl dt span.classifier:before{content:" : "}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code,html.writer-html4 .rst-content dl:not(.docutils) tt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js deleted file mode 100644 index daccd209dab05a75f5627390e37a6b764e93f547..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/doctools.js +++ /dev/null @@ -1,315 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js deleted file mode 100644 index dfb1e34c67417d2441d319ead26fe08a1de8ace9..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,12 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.0.1', - LANGUAGE: 'zh_CN', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/file.png and /dev/null differ diff --git a/docs/_build/html/_static/fonts/FontAwesome.otf b/docs/_build/html/_static/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f36e4f73b8efa40bd6f604fe80d286db70..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/FontAwesome.otf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.eot b/docs/_build/html/_static/fonts/Lato/lato-bold.eot deleted file mode 100644 index 3361183a419c188282a8545eaa8d8e298b8ffaab..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bold.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.ttf b/docs/_build/html/_static/fonts/Lato/lato-bold.ttf deleted file mode 100644 index 29f691d5ed0c2d3d224423bb0288e6bd59292511..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bold.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.woff b/docs/_build/html/_static/fonts/Lato/lato-bold.woff deleted file mode 100644 index c6dff51f063cc732fdb5fe786a8966de85f4ebec..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 b/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 deleted file mode 100644 index bb195043cfc07fa52741c6144d7378b5ba8be4c5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot deleted file mode 100644 index 3d4154936b42522fac84900c689a901ac12875c0..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf deleted file mode 100644 index f402040b3e5360b90f3a12ca2afab2cd7244e16f..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff deleted file mode 100644 index 88ad05b9ff413055b4d4e89dd3eec1c193fa20c6..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 deleted file mode 100644 index c4e3d804b57b625b16a36d767bfca6bbf63d414e..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.eot b/docs/_build/html/_static/fonts/Lato/lato-italic.eot deleted file mode 100644 index 3f826421a1d97b09797fad3d781a666a39eb45c9..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-italic.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.ttf b/docs/_build/html/_static/fonts/Lato/lato-italic.ttf deleted file mode 100644 index b4bfc9b24aa993977662352c881c6e42f99f77e0..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-italic.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.woff b/docs/_build/html/_static/fonts/Lato/lato-italic.woff deleted file mode 100644 index 76114bc03362242c3325ecda6ce6d02bb737880f..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-italic.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 b/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 deleted file mode 100644 index 3404f37e2e312757841abe20343588a7740768ca..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.eot b/docs/_build/html/_static/fonts/Lato/lato-regular.eot deleted file mode 100644 index 11e3f2a5f0f9b8c7ef6affae8c543d20f7c112be..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-regular.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.ttf b/docs/_build/html/_static/fonts/Lato/lato-regular.ttf deleted file mode 100644 index 74decd9ebb8d805201934266b3bda6a9d5831024..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-regular.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.woff b/docs/_build/html/_static/fonts/Lato/lato-regular.woff deleted file mode 100644 index ae1307ff5f4c48678621c240f8972d5a6e20b22c..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-regular.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 b/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 deleted file mode 100644 index 3bf9843328a6359b6bd06e50010319c63da0d717..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff b/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff deleted file mode 100644 index 6cb60000181dbd348963953ac8ac54afb46c63d5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff2 b/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff2 deleted file mode 100644 index 7059e23142aae3d8bad6067fc734a6cffec779c9..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff b/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff deleted file mode 100644 index 337d287116cd6540ec54f51b039a1c962dbcca7b..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff2 b/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff2 deleted file mode 100644 index 20398aff31abb093abaafcc1d9bf5418ac437139..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Light.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff b/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff deleted file mode 100644 index f815f63f99da80ad2be69e4021023ec2981eaea0..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff2 b/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff2 deleted file mode 100644 index f2c76e5bda18a9842e24cd60d8787257da215ca7..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Regular.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff b/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff deleted file mode 100644 index 6b30ea630d5259514afaaa6cad000336226c2fd8..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff2 b/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff2 deleted file mode 100644 index 328f5bb042838089a40d0125728f9f47747d6c27..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/Roboto-Slab-Thin.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot deleted file mode 100644 index 79dc8efed3447d6588baa2bb74122d56f3500038..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf deleted file mode 100644 index df5d1df2730433013f41bf2698cbe249b075aa02..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff deleted file mode 100644 index 6cb60000181dbd348963953ac8ac54afb46c63d5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 deleted file mode 100644 index 7059e23142aae3d8bad6067fc734a6cffec779c9..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot deleted file mode 100644 index 2f7ca78a1eb34f0f98feb07ab1231d077b248940..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf deleted file mode 100644 index eb52a7907362cc3392eb74892883f5d9e260b638..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff deleted file mode 100644 index f815f63f99da80ad2be69e4021023ec2981eaea0..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 deleted file mode 100644 index f2c76e5bda18a9842e24cd60d8787257da215ca7..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.eot b/docs/_build/html/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca953f93e35eab4108bd414bc02ddcf3928..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.svg b/docs/_build/html/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e538b65548118279537a04eab2ec6ef0d..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.ttf b/docs/_build/html/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1196aad98c2adf4378a7611dd713aa3..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.woff b/docs/_build/html/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b06eee3d0c0d54402a47ab2601b2862b..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 b/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60404b91e398a37200c4a77b645cfd9586..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-bold-italic.woff b/docs/_build/html/_static/fonts/lato-bold-italic.woff deleted file mode 100644 index 88ad05b9ff413055b4d4e89dd3eec1c193fa20c6..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-bold-italic.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-bold-italic.woff2 b/docs/_build/html/_static/fonts/lato-bold-italic.woff2 deleted file mode 100644 index c4e3d804b57b625b16a36d767bfca6bbf63d414e..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-bold-italic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-bold.woff b/docs/_build/html/_static/fonts/lato-bold.woff deleted file mode 100644 index c6dff51f063cc732fdb5fe786a8966de85f4ebec..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-bold.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-bold.woff2 b/docs/_build/html/_static/fonts/lato-bold.woff2 deleted file mode 100644 index bb195043cfc07fa52741c6144d7378b5ba8be4c5..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-bold.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-normal-italic.woff b/docs/_build/html/_static/fonts/lato-normal-italic.woff deleted file mode 100644 index 76114bc03362242c3325ecda6ce6d02bb737880f..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-normal-italic.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-normal-italic.woff2 b/docs/_build/html/_static/fonts/lato-normal-italic.woff2 deleted file mode 100644 index 3404f37e2e312757841abe20343588a7740768ca..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-normal-italic.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-normal.woff b/docs/_build/html/_static/fonts/lato-normal.woff deleted file mode 100644 index ae1307ff5f4c48678621c240f8972d5a6e20b22c..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-normal.woff and /dev/null differ diff --git a/docs/_build/html/_static/fonts/lato-normal.woff2 b/docs/_build/html/_static/fonts/lato-normal.woff2 deleted file mode 100644 index 3bf9843328a6359b6bd06e50010319c63da0d717..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/_static/fonts/lato-normal.woff2 and /dev/null differ diff --git a/docs/_build/html/_static/jquery-3.5.1.js b/docs/_build/html/_static/jquery-3.5.1.js deleted file mode 100644 index 50937333b99a5e168ac9e8292b22edd7e96c3e6a..0000000000000000000000000000000000000000 --- a/docs/_build/html/_static/jquery-3.5.1.js +++ /dev/null @@ -1,10872 +0,0 @@ -/*! - * jQuery JavaScript Library v3.5.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2020-05-04T22:49Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.5.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.5 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2020-03-14 - */ -( function( window ) { -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = arr.push, - push = arr.push, - slice = arr.slice, - - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[ i ] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + - "ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] - // or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + - whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + - "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rhtml = /HTML$/i, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - return nonHex ? - - // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + - ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android<4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - - // Can't trust NodeList.length - while ( ( target[ j++ ] = els[ i++ ] ) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split( "|" ), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[ i ] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( ( cur = cur.nextSibling ) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return ( name === "input" || name === "button" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; - } ); - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert( function( el ) { - el.className = "i"; - return !el.getAttribute( "className" ); - } ); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert( function( el ) { - el.appendChild( document.createComment( "" ) ); - return !el.getElementsByTagName( "*" ).length; - } ); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find[ "TAG" ] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - assert( function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll( "[name=d]" ).length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: Opera 10 - 11 only - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll( "*,:x" ); - rbuggyQSA.push( ",.*:" ); - } ); - } - - if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector ) ) ) ) { - - assert( function( el ) { - - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - } ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); - } : - function( a, b ) { - if ( b ) { - while ( ( b = b.parentNode ) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { - - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a == document || a.ownerDocument == preferredDoc && - contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( b == document || b.ownerDocument == preferredDoc && - contains( preferredDoc, b ) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - return a == document ? -1 : - b == document ? 1 : - /* eslint-enable eqeqeq */ - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( ( cur = cur.parentNode ) ) { - ap.unshift( cur ); - } - cur = b; - while ( ( cur = cur.parentNode ) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[ i ] === bp[ i ] ) { - i++; - } - - return i ? - - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[ i ], bp[ i ] ) : - - // Otherwise nodes in our document sort first - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - ap[ i ] == preferredDoc ? -1 : - bp[ i ] == preferredDoc ? 1 : - /* eslint-enable eqeqeq */ - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( support.matchesSelector && documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch ( e ) { - nonnativeSelectorCache( expr, true ); - } - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( elem.ownerDocument || elem ) != document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[ 1 ] = match[ 1 ].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || - match[ 5 ] || "" ).replace( runescape, funescape ); - - if ( match[ 2 ] === "~=" ) { - match[ 3 ] = " " + match[ 3 ] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[ 1 ] = match[ 1 ].toLowerCase(); - - if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - - // nth-* requires argument - if ( !match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[ 4 ] = +( match[ 4 ] ? - match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); - match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - - // other types prohibit arguments - } else if ( match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[ 6 ] && match[ 2 ]; - - if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[ 3 ] ) { - match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - - // Get excess from tokenize (recursively) - ( excess = tokenize( unquoted, true ) ) && - - // advance to the next closing parenthesis - ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { - - // excess is a negative index - match[ 0 ] = match[ 0 ].slice( 0, excess ); - match[ 2 ] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { - return true; - } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - ( pattern = new RegExp( "(^|" + whitespace + - ")" + className + "(" + whitespace + "|$)" ) ) && classCache( - className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); - } ); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - /* eslint-disable max-len */ - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - /* eslint-enable max-len */ - - }; - }, - - "CHILD": function( type, what, _argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, _context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( ( node = node[ dir ] ) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( ( node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - - // Use previously-cached element index if available - if ( useCache ) { - - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - - // Use the same loop as above to seek `elem` from the start - while ( ( node = ++nodeIndex && node && node[ dir ] || - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || - ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction( function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[ i ] ); - seed[ idx ] = !( matches[ idx ] = matched[ i ] ); - } - } ) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - - // Potentially complex pseudos - "not": markFunction( function( selector ) { - - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction( function( seed, matches, _context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( ( elem = unmatched[ i ] ) ) { - seed[ i ] = !( matches[ i ] = elem ); - } - } - } ) : - function( elem, _context, xml ) { - input[ 0 ] = elem; - matcher( input, null, xml, results ); - - // Don't keep the element (issue #299) - input[ 0 ] = null; - return !results.pop(); - }; - } ), - - "has": markFunction( function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - } ), - - "contains": markFunction( function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; - }; - } ), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - - // lang value must be a valid identifier - if ( !ridentifier.test( lang || "" ) ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( ( elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); - return false; - }; - } ), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && - ( !document.hasFocus || document.hasFocus() ) && - !!( elem.type || elem.href || ~elem.tabIndex ); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return ( nodeName === "input" && !!elem.checked ) || - ( nodeName === "option" && !!elem.selected ); - }, - - "selected": function( elem ) { - - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos[ "empty" ]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( ( attr = elem.getAttribute( "type" ) ) == null || - attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo( function() { - return [ 0 ]; - } ), - - "last": createPositionalPseudo( function( _matchIndexes, length ) { - return [ length - 1 ]; - } ), - - "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - } ), - - "even": createPositionalPseudo( function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "odd": createPositionalPseudo( function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? - argument + length : - argument > length ? - length : - argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ) - } -}; - -Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || ( match = rcomma.exec( soFar ) ) ) { - if ( match ) { - - // Don't consume trailing commas as valid - soFar = soFar.slice( match[ 0 ].length ) || soFar; - } - groups.push( ( tokens = [] ) ); - } - - matched = false; - - // Combinators - if ( ( match = rcombinators.exec( soFar ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - - // Cast descendant combinators to space - type: match[ 0 ].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || - ( match = preFilters[ type ]( match ) ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[ i ].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || - ( outerCache[ elem.uniqueID ] = {} ); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( ( oldCache = uniqueCache[ key ] ) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return ( newCache[ 2 ] = oldCache[ 2 ] ); - } else { - - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[ i ]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[ 0 ]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[ i ], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( ( elem = unmatched[ i ] ) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( - selector || "*", - context.nodeType ? [ context ] : context, - [] - ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( ( elem = temp[ i ] ) ) { - matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) ) { - - // Restore matcherIn since elem is not yet a final match - temp.push( ( matcherIn[ i ] = elem ) ); - } - } - postFinder( null, ( matcherOut = [] ), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - - seed[ temp ] = !( results[ temp ] = elem ); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - } ); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[ 0 ].type ], - implicitRelative = leadingRelative || Expr.relative[ " " ], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - ( checkContext = context ).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { - matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; - } else { - matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[ j ].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens - .slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), - - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), - len = elems.length; - - if ( outermost ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( !context && elem.ownerDocument != document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( ( matcher = elementMatchers[ j++ ] ) ) { - if ( matcher( elem, context || document, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - - // They will have gone through all possible matchers - if ( ( elem = !matcher && elem ) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( ( matcher = setMatchers[ j++ ] ) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !( unmatched[ i ] || setMatched[ i ] ) ) { - setMatched[ i ] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[ i ] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( - selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) - ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( ( selector = compiled.selector || selector ) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[ 0 ] = match[ 0 ].slice( 0 ); - if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - - context = ( Expr.find[ "ID" ]( token.matches[ 0 ] - .replace( runescape, funescape ), context ) || [] )[ 0 ]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[ i ]; - - // Abort if we hit a combinator - if ( Expr.relative[ ( type = token.type ) ] ) { - break; - } - if ( ( find = Expr.find[ type ] ) ) { - - // Search, expanding context for leading sibling combinators - if ( ( seed = find( - token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || - context - ) ) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert( function( el ) { - - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; -} ); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert( function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute( "href" ) === "#"; -} ) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - } ); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert( function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -} ) ) { - addHandle( "value", function( elem, _name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - } ); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert( function( el ) { - return el.getAttribute( "disabled" ) == null; -} ) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; - } - } ); -} - -return Sizzle; - -} )( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, _i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, _i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, _i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( _i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, _key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = Object.create( null ); - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { - - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var notAsync, result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); - this[ type ](); - result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - return result.value; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { - - // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - delegateType: delegateType - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle events" ); - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var swap = function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px"; - tr.style.height = "1px"; - trChild.style.height = "9px"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( _elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( _i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( _i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + - uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { - s.converters[ "text script" ] = function() {}; - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( _i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - -jQuery.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

app2 module

-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/modules.html b/docs/_build/html/dts/modules.html deleted file mode 100644 index bc8f6c80955aac7c6be792a60bed296ff36d89d1..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/modules.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - - - pyminer — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - - - -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pmgwidgets.html b/docs/_build/html/dts/pmgwidgets.html deleted file mode 100644 index 54f16ebb91c660c4ce4f711e1d9dbc68635e2cf1..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pmgwidgets.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - - pmgwidgets package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
- -
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pmgwidgets.normal.html b/docs/_build/html/dts/pmgwidgets.normal.html deleted file mode 100644 index 56fafe6deeae4456886e4857604fc6936d8e749e..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pmgwidgets.normal.html +++ /dev/null @@ -1,620 +0,0 @@ - - - - - - - - - - pmgwidgets.normal package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pmgwidgets.normal package

-
-

Submodules

-
-
-

pmgwidgets.normal.value_inputs module

-
-
-class pmgwidgets.normal.value_inputs.AnyType(parent, title, types=['Int', 'Float', 'Str'])
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_text(event)
-
- -
-
-on_type(event)
-
- -
-
-set_value(v)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.BaseParamWidget
-

基类:PyQt5.QtWidgets.QWidget

-

基础参数控件的类型。所有的参数控件都在其上派生而来。

-
-
-get_value()
-
- -
-
-is_key(event, type='')
-

‘dir’:判断方向键 -‘alpha’:判断是否为26个字母 -‘hex’:判断是否为十六进制数字或者字母 -‘digit’:判断是否为数字0~9 -‘valid’:包含数字、字母或者退格键。

-
- -
-
-para_changed()
-
- -
-
-set_app(app)
-
- -
-
-set_value()
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Check(title: str, initial_value: bool)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-

bool, ‘sport’, ‘do you like sport’,True

-
-
-get_value()
-
- -
-
-on_check()
-
- -
-
-set_value(value: bool)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Choice(choices, tp, title, unit)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-get_value()
-
- -
-
-on_choice(event=None)
-
- -
-
-on_radio_button_toggled()
-
- -
-
-set_value(x)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Choices(parent, choices, title)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_check()
-
- -
-
-set_value(value: list)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.ColorCtrl(title: str, initial_value: str)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-colorStr2Tup(value: str) → tuple
-
- -
-
-colorTup2Str(value: tuple) → str
-
- -
-
-get_value()
-
- -
-
-oncolor(event)
-
- -
-
-ontext(event)
-
- -
-
-set_value(color)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.FloatSlider(parent, rang, accury, title, unit='')
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_scroll(event)
-

只有这个方法会调用回调函数。原因:当用户通过拖动滚动条进行操作的时候,输入的值一定是合理的,无需进行判断; -当用户通过按spinbox或者是对spinbox输入文本的时候,只有文本符合规定的时候会对slider设置值,此时会调用这个方法。 -这样总能调用到这个回调函数。

-
- -
-
-on_spin()
-
- -
-
-on_text(event)
-
- -
-
-set_para(rang, accury)
-
- -
-
-set_value(n)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Label(parent, title)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value(v)
-
- -
-
-set_value(v)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.NumCtrl(title: str, initial_value: int, unit: str, rang: tuple)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-

NumCtrl: derived from tk.Entry -用于输入数值。

-
-
-Bind(z, f)
-
- -
-
-Refresh()
-
- -
-
-f(e)
-
- -
-
-get_value()
-
- -
-
-ontext(event)
-
- -
-
-set_value(n)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.PathCtrl(parent, title, filt)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-get_value() → str
-
- -
-
-onselect(event)
-
- -
-
-ontext(event)
-
- -
-
-set_value(value: str)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.SettingsPanel(values: Dict = None, views: List[Tuple[str]] = None, parent=None)
-

基类:PyQt5.QtWidgets.QWidget

-
-
-closeEvent(self, QCloseEvent)
-
- -
-
-get_value()
-
- -
-
-widgets_dic: Dict[str, PyQt5.QtWidgets.QWidget] = {}
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.TextCtrl(title: str, initial_value: str)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value() → str
-
- -
-
-ontext(event)
-
- -
-
-param_changed(event)
-
- -
-
-set_value(text: str)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pmgwidgets.table.html b/docs/_build/html/dts/pmgwidgets.table.html deleted file mode 100644 index 46fd69d0d98485f06c348aa9f6d871fb296621d1..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pmgwidgets.table.html +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - - - pmgwidgets.table package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pmgwidgets.table package

-
-

Submodules

-
-
-

pmgwidgets.table.tableviews module

-

这是一个利用QT的MVC架构进行数据查看的表格。这个表格十分适合大量数据的查看,1000*1000规模的数据集可以做到秒开。 -其中定义了若干类。可以直接显示pd.DataFrame,np.array和list的TableView。

-
-
-class pmgwidgets.table.tableviews.PMTableView(data=None)
-

基类:PyQt5.QtWidgets.QTableView

-

基类,用于显示数据。输入数据类型为列表。

-
-
-set_data(data)
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForList(data: list)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为list的table model

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForNumpyArray(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForPandasDataframe(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-headerData(self, int, Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-pmgwidgets.table.tableviews.dataformat(val, decimals=6, sci=False)
-

这只是暂时的strformat函数。如有可能,应当使用cython重写并且部署在动态链接库中,从而提升性能。 -Args:

-
-

val: -decimals: -sci:

-
-

Returns:

-
- -
-
-pmgwidgets.table.tableviews.to_decimal_str(cell_data: numpy.ndarray, decimals: int = 6)
-
- -
-
-

pmgwidgets.table.tablewidgets module

-
-
-class pmgwidgets.table.tablewidgets.PMGTableTabWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTabWidget

-
- -
-
-class pmgwidgets.table.tablewidgets.PMGTableWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTableWidget

-
-
-static check_data_can_be_displayed_by_table(data: Sized) → bool
-
- -
-
-closeEvent(self, QCloseEvent)
-
- -
-
-data_name: str = ''
-
- -
-
-data_shown
-
- -
-
-set_data_2d(data: np.ndarray, rows: int = None, columns: int = None)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.extensionlib.html b/docs/_build/html/dts/pyminer2.extensions.extensionlib.html deleted file mode 100644 index e5f39a112552a1a85447a8d8d633ccdcc91ef829..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.extensionlib.html +++ /dev/null @@ -1,500 +0,0 @@ - - - - - - - - - - pyminer2.extensions.extensionlib package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.extensionlib package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.extensionlib package

-
-

Submodules

-
-
-

pyminer2.extensions.extensionlib.baseext module

-
-
-class pyminer2.extensions.extensionlib.baseext.BaseExtension
-

基类:object

-
-
-extension_lib: extension_lib = None
-
- -
-
-get_widget(name: str)
-
- -
-
-public_interface: BaseInterface = None
-
- -
-
-widget_classes: Dict[str, QWidget] = None
-
- -
-
-widgets: Dict[str, QWidget] = None
-
- -
- -
-
-class pyminer2.extensions.extensionlib.baseext.BaseInterface
-

基类:object

-
-
-hello()
-
- -
- -
-
-

pyminer2.extensions.extensionlib.extension_lib module

-
-
-pyminer2.extensions.extensionlib.extension_lib.wrapper()
-
- -
-
-

pyminer2.extensions.extensionlib.pmext module

-
-
-class pyminer2.extensions.extensionlib.pmext.PluginInterface
-

基类:object

-
-
-class Signals
-

基类:object

-
-
-static get_main_window_close_signal()
-
- -
- -
-
-static add_docked_widget(dock_name: str, widget: PyQt5.QtWidgets.QWidget, text: str, side: str = 'left')
-
- -
-
-static add_tool_bar(name: str, toolbar: PyQt5.QtWidgets.QToolBar, text: str)
-
- -
-
-static append_to_context_menu(text: str, command: Callable, icon_path: str)
-

添加到鼠标右键菜单当中。 -Args:

-
-

text: -command: -icon_path:

-
-

Returns:

-
- -
-
-static append_to_sidebar(text: str, command: Callable, icon_path: str)
-

添加到右侧工具栏中。 -Args:

-
-

text:工具栏显示的文字。一般时候工具栏的文字是不会显示在界面上的,但鼠标悬停时会显示出来。 -command: 点击时调用的函数 -icon_path: 图标的文件路径,不得为空。

-
-

Returns:None

-
- -
-
-static append_to_toolbar(toolbar_name: str, text: str, icon: PyQt5.QtGui.QIcon, menu: PyQt5.QtWidgets.QMenu) → PyQt5.QtWidgets.QToolButton
-
-
Args:

text:工具栏显示的文字。一般时候工具栏的文字是不会显示在界面上的,但鼠标悬停时会显示出来。 -icon: 图标 -toolbar_name:工具栏的名称。

-
-
-

Returns:None

-
- -
-
-static append_to_toolbox(tab_id: int, icon_path: str, text: str, command: callable)
-

插入到工具箱中按钮。 -Args:

-
-

tab_id: -icon_path: -text: -command:

-
-

Returns:

-
- -
-
-static append_to_tray_menu(text: str, command: Callable)
-

添加到托盘菜单栏。 -Args:

-
-

text: 菜单的文字内容 -command: 点击菜单触发的函数

-
-

Returns:

-
- -
-
-static append_widget_to_toolbar(toolbar_name: str, widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-static get_console() → ConsoleWidget
-

获取控制台的实例。

-
- -
-
-static get_data_manager() → DataManager
-

# 获取数据管理类,返回DataManager

-
- -
-
-static get_dialog_class(dialog_name: str)
-

获取对话框类的方式。

-
- -
-
-static get_editor() → PMCodeEditTabWidget
-
- -
-
-static get_root_dir() → str
-

获取项目的根目录

-
- -
-
-static get_toolbar(toolbar_name: str) → PMToolBar
-

获取工具栏 -:param toolbar_name: -:return:

-
- -
-
-static get_toolbar_widget(toolbar_name: str, tool_widget_name: str) → PyQt5.QtWidgets.QPushButton
-
- -
-
-static get_work_dir() → str
-

获取当前工作路径

-
- -
-
-static get_workspace_inspector() → PMWorkspaceInspectWidget
-
- -
-
-static set_work_dir(work_dir: str) → None
-

设置当前工作路径

-
- -
-
-static show_dialog(dialog_name: str, parent=None, args=())
-

对话框类必须有parent作为输入参数。否则对话框将无法显示。 -另外还可以通过args选项指定除了parent之外的其他输入参数。

-
- -
-
-static show_log(level: str, module: str, content: str)
-

在日志窗口显示log。 -:param level: 类型,比如‘info’ -:param module: 模块。比如’Jupyter’ -:param content: 内容。自定义的字符串 -:return: -效果: -调用——PluginInterface.show_log(‘info’,’CodeEditor’,’新建文件’) -输出——2020-08-29 23:43:10 hzy INFO [CodeEditor]:新建文件

-
- -
-
-static show_tool_bar(toolbar_name: str)
-

切换工具栏 -:param toolbar_name: -:return:

-
- -
-
-static switch_tool_bar(toolbar_name: str)
-

切换工具栏 -:param toolbar_name: -:return:

-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.extensions_manager.html b/docs/_build/html/dts/pyminer2.extensions.extensions_manager.html deleted file mode 100644 index 3512fc6d41751ddb0866c858da40a4ae51578e4d..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.extensions_manager.html +++ /dev/null @@ -1,488 +0,0 @@ - - - - - - - - - - pyminer2.extensions.extensions_manager package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.extensions_manager package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.extensions_manager package

-
-

Submodules

-
-
-

pyminer2.extensions.extensions_manager.ExtensionLoader module

-
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.ExtensionLoader
-

基类:object

-
-
-binding_info()
-
- -
-
-create_public_interface(interface)
-
- -
-
-import_module(path)
-
- -
-
-load(file, ui_inserters)
-
- -
-
-load_class(file, class_name)
-
- -
-
-load_widget(widget_config)
-
- -
-
-reset()
-
- -
- -
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.Info(icon, name, display_name, version, description, path)
-

基类:tuple

-
-
-property description
-

Alias for field number 4

-
- -
-
-property display_name
-

Alias for field number 2

-
- -
-
-property icon
-

Alias for field number 0

-
- -
-
-property name
-

Alias for field number 1

-
- -
-
-property path
-

Alias for field number 5

-
- -
-
-property version
-

Alias for field number 3

-
- -
- -
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.PublicInterface
-

基类:object

-
- -
-
-

pyminer2.extensions.extensions_manager.UIInserter module

-

控件插入器 -作者:冰中火,侯展意

-

这是加载UI控件的插件类。 -插件导入的时候,传递的widget_class是控件的类。 -1、对于新建的工具栏类、插入工具栏的控件类、插入主窗口的控件类,控件插入器直接将控件类实例化, -然后插入在由config.json中指定的位置; -2、对于对话框类,控件插入器不会将其实例化,而会将其保存在对话框类管理器中。使用时,调用相应的方法,可以显示对话框。 -请注意,对话框并不是什么只能问问题,点‘确定、取消’的类。只要继承QDialog的界面都要这样处理。 -以上1中所述的情况将在应用初始化时完成;而2则是动态的过程,可以在应用初始化完成后就弹出对话框进行显示。

-

插件导入时参数由json中的config设置项所决定。

-

config:是一个字典,但是现在传入的参数还远远不够。 -以这个文件的json配置为例,有以下要求: -“file”:声明了控件类的入口位置。一般就是在main.py之中。 -position:插件插入位置。有两种选项:‘new_dock_window’和‘new_toolbar’ -config:设置属性。 -config.message:插件的设置信息,可以为空。 -config.name:插件的名称 -config.side:插件插入窗口时的位置(当position=new_dock_window时有效),有left -ight opottom四个选项 -config.text:插件的文字。会显示在dockwidget或者工具栏上 -{

-
-

“file”:”main.py”, -“widget_class”:”WidgetTest”, -“position”:”new_dock_window”, -“config”:{

-
-

“message”:”no”, -“name”:”code_editor”, -“side”: “right”, -“text”: “编辑器”

-
-

}

-
-

}

-

插件管理器下一步的目的就是将插件尽可能不一次性的加载完,插件可以自行设置插入到程序的时间, -尽可能在主界面发出初始化完成信号之后在进行调用。

-
-
-class pyminer2.extensions.extensions_manager.UIInserter.UiInserter
-

基类:dict

-
-
-append_to_toolbar(widget_class: QWidget, config=None)
-
- -
-
-new_dock_window(widget_class: QWidget, config=None)
-
- -
-
-new_toolbar(widget_class: QWidget, config=None)
-
- -
- -
-
-pyminer2.extensions.extensions_manager.UIInserter.get_dock_by_position(pos: str)
-
- -
-
-pyminer2.extensions.extensions_manager.UIInserter.get_item_coor(coors: set, pos: str)
-
- -
-
-

pyminer2.extensions.extensions_manager.log module

-
-
-pyminer2.extensions.extensions_manager.log.assert_(boolean, text)
-

boolean:bool -text:str -若bool为false,以异常级输出text

-
- -
-
-pyminer2.extensions.extensions_manager.log.error(text)
-
- -
-
-pyminer2.extensions.extensions_manager.log.log(text)
-

日志输出text

-
- -
-
-

pyminer2.extensions.extensions_manager.manager module

-
-
-class pyminer2.extensions.extensions_manager.manager.ExtensionsManager
-

基类:object

-

扩展管理类

-
-
-get_ext_by_id(id_)
-

通过id获取扩展

-
- -
-
-get_ext_by_name(name)
-

通过名称获取扩展

-
- -
-
-install(path)
-

本地安装扩展

-
- -
-
-install_web(name, version='')
-
- -
-
-load()
-

加载扩展

-
- -
-
-load_one(name)
-
- -
-
-uninstall(id_)
-

卸载扩展

-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.html b/docs/_build/html/dts/pyminer2.extensions.html deleted file mode 100644 index 0af75c869fb8a8c1bb93fefa387b314f8d2dd2a7..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - - pyminer2.extensions package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
- -
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.package_manager.html b/docs/_build/html/dts/pyminer2.extensions.package_manager.html deleted file mode 100644 index 222f776d53d31baf9c81936c0e46dc835985e5cf..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.package_manager.html +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - - - pyminer2.extensions.package_manager package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.package_manager package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.package_manager package

-
-

Submodules

-
-
-

pyminer2.extensions.package_manager.env_manager module

-
-
-class pyminer2.extensions.package_manager.env_manager.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_install module

-
-
-class pyminer2.extensions.package_manager.package_install.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_manager module

-
-
-

pyminer2.extensions.package_manager.package_remove module

-
-
-class pyminer2.extensions.package_manager.package_remove.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_setting module

-
-
-class pyminer2.extensions.package_manager.package_setting.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_update module

-
-
-class pyminer2.extensions.package_manager.package_update.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.html b/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.html deleted file mode 100644 index 35757102971fd9b3efe99a4b3b4d24f0a74aad57..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - - pyminer2.extensions.test_demo.extensions package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - - - -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension.html b/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension.html deleted file mode 100644 index eb327e3da6953a2c2a259858f0f3eab397c222c3..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension.html +++ /dev/null @@ -1,315 +0,0 @@ - - - - - - - - - - pyminer2.extensions.test_demo.extensions.test_extension package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.test_demo.extensions.test_extension package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.test_demo.extensions.test_extension package

-
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensions.test_extension.entry module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.entry.MyEntry(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Entry

-
-
-run()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.interface module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.interface.MyInterface
-

基类:object

-
-
-method()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.menu module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.menu.MyMenu(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Menu

-
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.subwindow module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow1(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow2(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension2.html b/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension2.html deleted file mode 100644 index f11f3b9dee810d5f1d7b920d1ede4b29a1f3fc54..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.test_demo.extensions.test_extension2.html +++ /dev/null @@ -1,315 +0,0 @@ - - - - - - - - - - pyminer2.extensions.test_demo.extensions.test_extension2 package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.test_demo.extensions.test_extension2 package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.test_demo.extensions.test_extension2 package

-
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.entry module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.entry.YourEntry(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Entry

-
-
-run()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.interface module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.interface.YourInterface
-

基类:object

-
-
-method()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.menu module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.menu.YourMenu(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Menu

-
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.subwindow module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow1(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow2(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.extensions.test_demo.html b/docs/_build/html/dts/pyminer2.extensions.test_demo.html deleted file mode 100644 index cf7fed8ae62f7b38741a2f8dd5bd2e70dc0a247a..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.extensions.test_demo.html +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - - - - - pyminer2.extensions.test_demo package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.extensions.test_demo package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.extensions.test_demo package

- -
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensionlib module

-
-
-class pyminer2.extensions.test_demo.extensionlib.DataClient
-

基类:object

-

This class provides methods for data exchange -with the data server. Instances of this class -can be created in entry’s run function. The -variables should be a JSON object that contains -varnames and corresponding values.

-
-
-lock(varname: str)
-
- -
-
-read(varname: str) → object
-
- -
-
-read_and_write(varname: str, write_func)
-
- -
-
-unlock(varname: str)
-
- -
-
-write(variables: dict)
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.Entry(config: dict)
-

基类:object

-
-
-get_dependency_interface(extension_name: str) → object
-
- -
-
-get_interface() → object
-
- -
-
-run()
-
- -
-
-start_menu(config: dict)pyminer2.extensions.test_demo.extensionlib.Menu
-
- -
-
-start_subWindow(subWindow_class: str, config: dict)pyminer2.extensions.test_demo.extensionlib.SubWindow
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.Menu(config: dict)
-

基类:object

-

Do not create instance of this class, implement -it and call the function start_menu in entry -class to get its instance.

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.SubWindow(config: dict)
-

基类:object

-

Do not create instance of this class, implement -it and call the function start_subwindow in -entry class to get its instance.

-
-
-test()
-
- -
- -
-
-

pyminer2.extensions.test_demo.mainform module

-
-
-class pyminer2.extensions.test_demo.mainform.Extension(info)
-

基类:object

-
-
-dynamic_binding()
-
- -
-
-end()
-
- -
-
-get_interface()
-
- -
-
-import_module(module_name)
-
- -
-
-life_period(run, extension)
-
- -
-
-start()
-
- -
-
-start_menu(config: dict)pyminer2.extensions.test_demo.extensionlib.Menu
-
- -
-
-start_subwindow(subwindow_class: str, config: dict)pyminer2.extensions.test_demo.extensionlib.SubWindow
-
- -
-
-wrap_interface(original_interface)
-
- -
- -
-
-class pyminer2.extensions.test_demo.mainform.MainForm
-

基类:object

-
-
-end_extension(extension: pyminer2.extensions.test_demo.mainform.Extension)
-
- -
-
-flush()
-

test only

-
- -
-
-get_dependency_interface(extension_name: str) → object
-
- -
-
-load_extension(extension_package: str)
-
- -
-
-run_extension(extension_name: str)
-
- -
-
-start_extension(extension: pyminer2.extensions.test_demo.mainform.Extension)
-
- -
-
-start_menu(start_menu)
-
- -
-
-start_subwindow(start_subwindow)
-
- -
- -
-
-pyminer2.extensions.test_demo.mainform.main()
-
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.html b/docs/_build/html/dts/pyminer2.html deleted file mode 100644 index c070560095a969d94dab607688947883d85e96f6..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.html +++ /dev/null @@ -1,403 +0,0 @@ - - - - - - - - - - pyminer2 package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2 package

-
-

Subpackages

-
- -
-
-
-

Submodules

-
-
-

pyminer2.pmappmodern module

-
-
-

pyminer2.pmutil module

-
-
-pyminer2.pmutil.get_application() → None
-

获取QApplication -Returns:

-
- -
-
-pyminer2.pmutil.get_main_window() → pyminer2.pmappmodern.MainWindow
-

获取主窗口或者主控件。 -Returns:

-
- -
-
-pyminer2.pmutil.get_root_dir() → str
-

获取根路径。 -Returns:

-
- -
-
-pyminer2.pmutil.get_work_dir() → str
-

获取主窗口或者主控件。 -Returns:

-
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.base.html b/docs/_build/html/dts/pyminer2.ui.base.html deleted file mode 100644 index e037eb5307b1aad1dda15b20e35f36c639ffbad6..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.base.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - - - - - pyminer2.ui.base package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
- -
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.base.widgets.html b/docs/_build/html/dts/pyminer2.ui.base.widgets.html deleted file mode 100644 index 201b49168ebc161c88eee9b8e8f2fa6494c41e53..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.base.widgets.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - - - - - - - pyminer2.ui.base.widgets package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui.base.widgets package

-
-

Submodules

-
-
-

pyminer2.ui.base.widgets.consolewidget module

-
-
-

pyminer2.ui.base.widgets.controlpanel module

-
-
-

pyminer2.ui.base.widgets.flowwidget module

-
-
-

pyminer2.ui.base.widgets.menu_tool_stat_bars module

-
-
-

pyminer2.ui.base.widgets.notificationwidget module

-
-
-

pyminer2.ui.base.widgets.reportwidget module

-
-
-

pyminer2.ui.base.widgets.resources module

-
-
-

pyminer2.ui.base.widgets.tablewidget module

-
-
-

pyminer2.ui.base.widgets.texteditconsolewidget module

-
-
-

pyminer2.ui.base.widgets.treeviews module

-
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.common.html b/docs/_build/html/dts/pyminer2.ui.common.html deleted file mode 100644 index 73afcf8510f69719c236103c4836188fb5b71442..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.common.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - - - - - pyminer2.ui.common package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui.common package

-
-

Submodules

-
-
-

pyminer2.ui.common.locale module

-
-
-class pyminer2.ui.common.locale.Locale
-

基类:object

-
-
-add_locale(locale_name: str, translations: Dict[str, str])
-
- -
-
-locale: str = 'zh'
-
- -
-
-translate(text: str) → str
-
- -
-
-translations: Dict[str, Dict] = {}
-
- -
-
-valid_locales: set = {'en', 'zh'}
-
- -
- -
-
-

pyminer2.ui.common.openprocess module

-
-
-class pyminer2.ui.common.openprocess.PMProcess(args: List[str])
-

基类:object

-
-
-consoleLoop()
-
- -
-
-enqueue_stream(stream, queue, type)
-
- -
- -
-
-

pyminer2.ui.common.platformutil module

-
-
-pyminer2.ui.common.platformutil.check_platform() → str
-
- -
-
-pyminer2.ui.common.platformutil.run_command_in_terminal(cmd: str, close_mode: str = 'wait_key')
-
- -
-
-

pyminer2.ui.common.test_comm module

-
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.basicwidgets.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.basicwidgets.html deleted file mode 100644 index 6e91a642b1b6ed66903c896315ca121e3c13a2b3..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.basicwidgets.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.basicwidgets package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.basicwidgets package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.basicwidgets package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.basicwidgets.labels module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.labels.PMScrollableLabel(parent=None)
-

基类:PyQt5.QtWidgets.QWidget

-
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.object module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.object.PMDockObject
-

基类:object

-
-
-on_closed_action = 'hide'
-
- -
-
-on_dock_widget_deleted()
-
- -
-
-raise_widget_to_visible(widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-signal_raise_into_view
-
- -
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons.PMPushButtonPane
-

基类:PyQt5.QtWidgets.QWidget

-
-
-add_button(text: str = '', icon: PyQt5.QtGui.QIcon = None, menu: PyQt5.QtWidgets.QMenu = None, height: int = 30, font_size: int = 14) → PyQt5.QtWidgets.QPushButton
-
- -
-
-add_buttons(button_num: int = 2, text: list = None, icon_path: list = None, menu: list = None) → List[PyQt5.QtWidgets.QPushButton]
-
- -
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.toolbutton module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.toolbutton.PMToolButton(parent=None)
-

基类:PyQt5.QtWidgets.QToolButton

-
-
-set_btn_clicked_effect()
-
- -
-
-shadow = <PyQt5.QtWidgets.QGraphicsDropShadowEffect object>
-
- -
-
-unset_btn_clicked_effect()
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.browser.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.browser.html deleted file mode 100644 index 6eec9714706ff7967fb5440253322579b498c1eb..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.browser.html +++ /dev/null @@ -1,256 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.browser package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.browser package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.browser package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.browser.browser module

-
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.containers.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.containers.html deleted file mode 100644 index c3502fba4a6d170f08dccdb0d6ecd854806997c7..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.containers.html +++ /dev/null @@ -1,341 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.containers package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.containers package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.containers package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.containers.PMTab module

-
-
-class pyminer2.ui.generalwidgets.containers.PMTab.PMTabWidget
-

基类:PyQt5.QtWidgets.QTabWidget

-
-
-addScrolledAreaTab(widget: PyQt5.QtWidgets.QWidget, a1: str) → int
-

添加使用QScrollArea包裹的Tab。 -:param widget: -:param a1: -:return:

-
- -
-
-setup_ui()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.containers.flowarea module

-

集成了流式布局、按钮排布的窗口。

-
-
-class pyminer2.ui.generalwidgets.containers.flowarea.PMFlowArea(parent=None)
-

基类:PyQt5.QtWidgets.QScrollArea

-
-
-add_tool_button(name: str, text: str, icon_path: str = '')
-
- -
-
-add_widget(w: PyQt5.QtWidgets.QWidget)
-
- -
-
-set_layout_content_margins(left: int, right: int, up: int, down: int)
-
- -
-
-setup_ui()
-
- -
- -
-
-class pyminer2.ui.generalwidgets.containers.flowarea.PMFlowAreaWidget
-

基类:PyQt5.QtWidgets.QWidget

-
-
-add_widget(w: PyQt5.QtWidgets.QWidget)
-
- -
-
-resizeEvent(self, QResizeEvent)
-
- -
-
-setup_ui()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.containers.pmscrollarea module

-
-
-class pyminer2.ui.generalwidgets.containers.pmscrollarea.PMScrollArea
-

基类:PyQt5.QtWidgets.QScrollArea

-
-
-setup_ui()
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.demos_and_tests.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.demos_and_tests.html deleted file mode 100644 index d3ba89d4bdd3df10282f11f81663b3867fc38ff4..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.demos_and_tests.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.demos_and_tests package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.demos_and_tests package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.demos_and_tests package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo module

-
-
-class pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo.Demo
-

基类:PyQt5.QtWidgets.QWidget

-
-
-A()
-
- -
-
-B(action)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.html deleted file mode 100644 index 3678a1ba6426e0277c348fd7f72c329a55bec587..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.html +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets package

-
-

Subpackages

-
- -
-
-
-

Module contents

-

generalwidgets是PyMiner继承于PyQt5的标准控件库。这个控件库封装PyQt中的标准控件,进行样式或者布局等等的设置,最终得到PyMiner需要的部件。

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.layouts.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.layouts.html deleted file mode 100644 index fad2c8d776874959577fa22738327e05a1ee73f8..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.layouts.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.layouts package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.layouts package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.layouts package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.layouts.flowlayout module

-
-
-class pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayout(parent=None, initial_columns=3, column_width=100)
-

基类:PyQt5.QtWidgets.QGridLayout

-
-
-add_widget(w: PyQt5.QtWidgets.QWidget) → None
-

添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 -:param w: -:param row: -:param column: -:param rowSpan: -:param columnSpan: -:return:

-
- -
-
-on_resize()
-

在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: -注意这个方法无法自动调用,只能依靠它的父控件。 -1 2 3 4 -5 6 7 8 -9 -:return:

-
- -
- -
-
-class pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayoutWithGrid(parent=None, column_width=100)
-

基类:PyQt5.QtWidgets.QGridLayout

-

流式布局,继承自QGridLayout,以Grid的方式添加widget。 -主要作用是在保证兼容代码的基础上,做到流式布局。

-
-
-addWidget(w: PyQt5.QtWidgets.QWidget, row: int, column: int, rowSpan: int, columnSpan: int) → None
-

添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 -:param w: -:param row: -:param column: -:param rowSpan: -:param columnSpan: -:return:

-
- -
-
-on_resize()
-

在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: -注意这个方法无法自动调用,只能依靠它的父控件。 -1 2 3 4 -5 6 7 8 -9 -:return:

-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.sourcemgr.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.sourcemgr.html deleted file mode 100644 index a01e9ba26cb24531e8019831f8096ff3bc7380dc..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.sourcemgr.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.sourcemgr package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.sourcemgr package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.sourcemgr package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.sourcemgr.iconutils module

-
-
-pyminer2.ui.generalwidgets.sourcemgr.iconutils.create_icon(icon_path: str = ':/pyqt/source/images/New.png')
-
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.table.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.table.html deleted file mode 100644 index c3ab7a77da986bce3e20d9178ae04ac0cb1e9485..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.table.html +++ /dev/null @@ -1,394 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.table package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.table package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.table package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.table.tableviews module

-

这是一个利用QT的MVC架构进行数据查看的表格。这个表格十分适合大量数据的查看,1000*1000规模的数据集可以做到秒开。 -其中定义了若干类。可以直接显示pd.DataFrame,np.array和list的TableView。

-
-
-class pyminer2.ui.generalwidgets.table.tableviews.PMTableView(data=None)
-

基类:PyQt5.QtWidgets.QTableView

-

基类,用于显示数据。输入数据类型为列表。

-
-
-set_data(data)
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForList(data: list)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为list的table model

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForNumpyArray(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForPandasDataframe(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-headerData(self, int, Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-pyminer2.ui.generalwidgets.table.tableviews.dataformat(val, decimals=6, sci=False)
-

这只是暂时的strformat函数。如有可能,应当使用cython重写并且部署在动态链接库中,从而提升性能。 -Args:

-
-

val: -decimals: -sci:

-
-

Returns:

-
- -
-
-

pyminer2.ui.generalwidgets.table.tablewidgets module

-
-
-class pyminer2.ui.generalwidgets.table.tablewidgets.PMGTableTabWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTabWidget

-
- -
-
-class pyminer2.ui.generalwidgets.table.tablewidgets.PMGTableWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTableWidget

-
-
-static check_data_can_be_displayed_by_table(data: object) → bool
-
- -
-
-closeEvent(self, QCloseEvent)
-
- -
-
-data_name: str = ''
-
- -
-
-data_shown
-
- -
-
-set_data_2d(data_name, data: np.ndarray, rows: int = None, columns: int = None)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.textctrls.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.textctrls.html deleted file mode 100644 index 419c33a27ff98ba6428dddeee4a869f612b5b832..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.textctrls.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.textctrls package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.textctrls package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.textctrls package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.textctrls.highlighter module

-
-
-class pyminer2.ui.generalwidgets.textctrls.highlighter.PythonHighlighter(parent=None)
-

基类:PyQt5.QtGui.QSyntaxHighlighter

-
-
-Formats = {}
-
- -
-
-Rules = []
-
- -
-
-highlightBlock(self, str)
-
- -
-
-static initializeFormats()
-
- -
-
-rehighlight(self)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.textctrls.textctrl module

-
-
-class pyminer2.ui.generalwidgets.textctrls.textctrl.PMGCodeEdit(parent=None)
-

基类:PyQt5.QtWidgets.QTextEdit

-
-
-autocomp_show(completions: list)
-
- -
-
-comment()
-
- -
-
-editIndent()
-
- -
-
-editUnindent()
-
- -
-
-hide_autocomp()
-
- -
-
-keyPressEvent(self, QKeyEvent)
-
- -
-
-on_back_tab()
-
- -
-
-on_backspace(key_backspace_event: PyQt5.QtGui.QKeyEvent)
-
- -
-
-on_close_request()
-
- -
-
-on_return_pressed()
-

按回车换行的方法 -:return:

-
- -
-
-on_tab()
-
- -
-
-on_text_changed()
-
- -
-
-save()
-
- -
-
-signal_save
-
- -
-
-updateUi()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module

-
-
-class pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.PMEditorWithLineNumber(parent=None)
-

基类:PyQt5.QtWidgets.QTextEdit

-
-
-highlightCurrentLine()
-
- -
-
-keyPressEvent(self, QKeyEvent)
-
- -
-
-lineNumberAreaPaintEvent(event)
-
- -
-
-lineNumberAreaWidth()
-
- -
-
-mousePressEvent(self, QMouseEvent)
-
- -
-
-on_scroll(event: PyQt5.QtGui.QWheelEvent = None)
-
- -
-
-resizeEvent(self, QResizeEvent)
-
- -
-
-updateLineNumberArea(rect, dy)
-
- -
-
-updateLineNumberAreaWidth(e)
-
- -
-
-wheelEvent(self, QWheelEvent)
-
- -
- -
-
-class pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.QLineNumberArea(editor)
-

基类:PyQt5.QtWidgets.QWidget

-
-
-paintEvent(self, QPaintEvent)
-
- -
-
-sizeHint(self) → QSize
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.toolbars.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.toolbars.html deleted file mode 100644 index cdddeee4f9fe867f6e9e48762ede315e0cad67d4..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.toolbars.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.toolbars package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.toolbars package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.toolbars package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.toolbars.toolbar module

-
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.ActionWithMessage(text: str = '', icon: PyQt5.QtGui.QIcon = None, parent: PyQt5.QtWidgets.QWidget = None, message: str = '')
-

基类:PyQt5.QtWidgets.QAction

-
- -
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.PMToolBar
-

基类:PyQt5.QtWidgets.QToolBar

-
-
-add_buttons(button_num: int, names: List[str], texts: List[str], icons_path: List[str] = None) → List[PyQt5.QtWidgets.QPushButton]
-
- -
-
-add_menu_to(button_name: str, action_texts: List[str], action_commands: List[Callable]) → List[PyQt5.QtWidgets.QAction]
-
- -
-
-add_tool_button(name: str, text: str = '', icon: PyQt5.QtGui.QIcon = None, menu: PyQt5.QtWidgets.QMenu = None)
-
- -
-
-add_widget(name: str, widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-get_control_widget(widget_name: str) → PyQt5.QtWidgets.QPushButton
-
- -
-
-tab_button: PyQt5.QtWidgets.QPushButton = None
-
- -
- -
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.TopToolBar
-

基类:PyQt5.QtWidgets.QToolBar

-
-
-add_button(text: str)
-
- -
-
-get_button(name: str)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.generalwidgets.window.html b/docs/_build/html/dts/pyminer2.ui.generalwidgets.window.html deleted file mode 100644 index 57e6ed4d52a38949c0f1c507fd96b1dc760ecc46..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.generalwidgets.window.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - - - - pyminer2.ui.generalwidgets.window package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.ui.generalwidgets.window package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.ui.generalwidgets.window package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.window.applicationtest module

-
-
-class pyminer2.ui.generalwidgets.window.applicationtest.MainWindow(parent=None)
-

基类:PyQt5.QtWidgets.QMainWindow, pyminer2.ui.generalwidgets.window.applicationtest.Ui_Form

-
- -
-
-class pyminer2.ui.generalwidgets.window.applicationtest.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.window.mainwindow_new module

-
-
-class pyminer2.ui.generalwidgets.window.mainwindow_new.MainWindow(parent=None)
-

基类:PyQt5.QtWidgets.QMainWindow, pyminer2.ui.generalwidgets.window.mainwindow_new.Ui_Form

-
- -
-
-class pyminer2.ui.generalwidgets.window.mainwindow_new.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.window.pmdockwidget module

-
-
-class pyminer2.ui.generalwidgets.window.pmdockwidget.PMDockWidget(name, text='', parent: PyQt5.QtWidgets.QMainWindow = None)
-

基类:pyminer2.ui.generalwidgets.window.pmdockwidget.PMGDockWidget

-
-
-closeEvent(self, QCloseEvent)
-
- -
-
-raise_into_view()
-

将控件提升到能直接看到的位置。特别适用于两个选项卡叠在一起的情况。 -:return:

-
- -
- -
-
-class pyminer2.ui.generalwidgets.window.pmdockwidget.PMGDockWidget(name, text='', parent: PyQt5.QtWidgets.QMainWindow = None)
-

基类:PyQt5.QtWidgets.QDockWidget

-
- -
-
-

pyminer2.ui.generalwidgets.window.pmmainwindow module

-

这里定义了MainWindow的基类。 -基类主要包含带选项卡工具栏的管理功能,以及浮动窗口的管理功能 -添加浮动窗口时,默认‘关闭’事件就是隐藏。如果是彻底的关闭,需要进行重写。 -每次界面关闭时,布局会被存入文件pyminer/config/customized/layout.ini之中。再次启动时,若这个文件存在,就会加载,反之不会加载。

-
-
-class pyminer2.ui.generalwidgets.window.pmmainwindow.BaseMainWindow
-

基类:PyQt5.QtWidgets.QMainWindow

-
-
-add_widget_on_dock(dock_name: str, widget: PyQt5.QtWidgets.QWidget, text: str = '', side='left')
-
- -
-
-bind_events()
-

在启动的最后调用这个绑定事件的方法,让全部的控件都绑定事件。这样可以避免绑定的时候,由于对应控件未加载,发生找不到对应控件的错误 -:return:

-
- -
-
-delete_dock_widget(widget_name: str)
-

删除dock_widget。 -:param widget_name: -:return:

-
- -
-
-dialog_classes: Dict[str, QDialog] = {}
-
- -
-
-dock_places = {'bottom': 8, 'left': 1, 'right': 2, 'top': 4}
-
- -
-
-dock_widgets: Dict[str, PMDockWidget] = {}
-
- -
-
-get_dock_widget(widget_name: str) → PMDockWidget
-
- -
-
-init_toolbar_tab()
-
- -
-
-load_layout()
-
- -
-
-load_predefined_layout(layout_type: str = 'standard')
-
- -
-
-load_settings()
-
- -
-
-on_boot_finished()
-
- -
-
-raise_dock_into_view(dock_name: str)
-
- -
-
-refresh_toolbar_appearance()
-
- -
-
-refresh_view_configs()
-
- -
-
-save_layout()
-
- -
-
-save_settings()
-
- -
-
-settings = {}
-
- -
-
-show_toolbar(name)
-
- -
-
-switch_toolbar(name: str)
-
- -
-
-toolbars: Dict[str, PyQt5.QtWidgets.QToolBar] = {}
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.html b/docs/_build/html/dts/pyminer2.ui.html deleted file mode 100644 index e08feea12c767738e9078ac24a46933ec2d5d29c..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.html +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - pyminer2.ui package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui package

-
-

Subpackages

-
- -
-
-
-

Submodules

-
-
-

pyminer2.ui.pyqtsource_rc module

-
-
-pyminer2.ui.pyqtsource_rc.qCleanupResources()
-
- -
-
-pyminer2.ui.pyqtsource_rc.qInitResources()
-
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.pmwidgets.html b/docs/_build/html/dts/pyminer2.ui.pmwidgets.html deleted file mode 100644 index 6fd694d90ad4672ba2f946d9ad4d3f307ee4e294..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.pmwidgets.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - - pyminer2.ui.pmwidgets package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui.pmwidgets package

-
-

Submodules

-
-
-

pyminer2.ui.pmwidgets.toplevel module

-
-
-class pyminer2.ui.pmwidgets.toplevel.TopLevelWidget(parent=None)
-

基类:PyQt5.QtWidgets.QDialog

-
-
-refresh_position() → None
-
- -
-
-set_central_widget(widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-set_position(position: PyQt5.QtCore.QPoint)
-
- -
-
-set_width(width: int)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.source.html b/docs/_build/html/dts/pyminer2.ui.source.html deleted file mode 100644 index 0d1de55d1ac32e6073699921ab72cb91c5dbb42e..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.source.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - - pyminer2.ui.source package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui.source package

- -
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.ui.source.qss.html b/docs/_build/html/dts/pyminer2.ui.source.qss.html deleted file mode 100644 index 7da328c7b586ca41461ceb24598535bb5e2c6fbb..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.ui.source.qss.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - - - - pyminer2.ui.source.qss package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

pyminer2.ui.source.qss package

-
-

Submodules

-
-
-

pyminer2.ui.source.qss.qss_tools module

-
-
-class pyminer2.ui.source.qss.qss_tools.QssTools
-

基类:object

-

定义一个读取样式的工具类

-
-
-classmethod set_qss_to_obj(file_path, obj)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.workspace.datamanager.html b/docs/_build/html/dts/pyminer2.workspace.datamanager.html deleted file mode 100644 index 2cdfce323b009c8d37a24a3f439316dbf23ae12f..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.workspace.datamanager.html +++ /dev/null @@ -1,664 +0,0 @@ - - - - - - - - - - pyminer2.workspace.datamanager package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • pyminer2.workspace.datamanager package
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

pyminer2.workspace.datamanager package

-
-

Submodules

-
-
-

pyminer2.workspace.datamanager.converter module

-
-
-class pyminer2.workspace.datamanager.converter.Converter(data_manager)
-

基类:object

-
-
-convert_dataframe(dataframe: pandas.core.frame.DataFrame) → dict
-
- -
-
-convert_list(lst: list) → dict
-
- -
-
-convert_ndarray(arr: numpy.ndarray) → dict
-
- -
-
-convert_to_data(var) → dict
-
- -
-
-convert_to_var(data: dict)
-
- -
-
-iconvert_dataframe(dataframe: pyminer2.workspace.datamanager.variable.Variable) → pandas.core.frame.DataFrame
-
- -
-
-iconvert_matrix(mat: pyminer2.workspace.datamanager.variable.Variable) → numpy.ndarray
-
- -
-
-iconvert_vector(vec: pyminer2.workspace.datamanager.variable.Variable) → numpy.ndarray
-
- -
- -
-
-exception pyminer2.workspace.datamanager.converter.ConverterError
-

基类:Exception

-
- -
-
-pyminer2.workspace.datamanager.converter.main()
-
- -
-
-

pyminer2.workspace.datamanager.datamanager module

-
-
-class pyminer2.workspace.datamanager.datamanager.DataManager
-

基类:object

-
-
-add_callbacks()
-
- -
-
-cancel(varname)
-
- -
-
-delete_data(varname: str)
-
- -
-
-get_all_var() → dict
-
- -
-
-get_data_info(varname: str) → dict
-
- -
-
-get_recyclebin() → list
-
- -
-
-get_var(varname: str)
-
- -
-
-lock_data(varname: str)
-
- -
-
-on_deletion(deletion_callback)
-
- -
-
-on_modification(modification_callback)
-
- -
-
-read_data(varname: str) → dict
-
- -
-
-redo(varname)
-
- -
-
-restore(index: int)
-
- -
-
-set_var(varname: str, variable, provider='unknown', **info)
-
- -
-
-set_var_dict(variables: dict, provider='unknown', info_dict: dict = {})
-
- -
-
-update_data_info(varname: str, **info)
-
- -
-
-write_data(varname: str, data: dict, provider='server')
-
- -
- -
-
-pyminer2.workspace.datamanager.datamanager.main()
-
- -
-
-

pyminer2.workspace.datamanager.dataset module

-
-
-class pyminer2.workspace.datamanager.dataset.DataSet
-

基类:dict

-
-
-compare(obj, req)
-
- -
-
-is_valid(obj: dict) → bool
-
- -
-
-read(key: str) → dict
-
- -
-
-select_type(type_name: str)
-
- -
-
-synchronise(key: str, obj: dict)
-
- -
-
-write(key: str, obj: dict)
-
- -
- -
-
-pyminer2.workspace.datamanager.dataset.main()
-
- -
-
-

pyminer2.workspace.datamanager.exceptions module

-
-
-exception pyminer2.workspace.datamanager.exceptions.ConflictError
-

基类:Exception

-
- -
-
-exception pyminer2.workspace.datamanager.exceptions.NotFoundError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.historyset module

-
-
-class pyminer2.workspace.datamanager.historyset.DataHistory(max_stack_num)
-

基类:list

-
-
-push(var)
-
- -
-
-stepback(var)
-
- -
-
-stepforward()
-
- -
- -
-
-exception pyminer2.workspace.datamanager.historyset.HistoryError
-

基类:Exception

-
- -
-
-class pyminer2.workspace.datamanager.historyset.HistorySet(max_stack_num=15)
-

基类:dict

-
-
-push(key: str, var)
-
- -
-
-stepback(key: str, var)
-
- -
-
-stepforward(key: str)
-
- -
- -
-
-

pyminer2.workspace.datamanager.metadataset module

-
-
-class pyminer2.workspace.datamanager.metadataset.MetaData(provider, **info)
-

基类:dict

-
- -
-
-class pyminer2.workspace.datamanager.metadataset.MetaDataSet
-

基类:dict

-
-
-define_data(key: str, info: pyminer2.workspace.datamanager.metadataset.MetaData)
-
- -
-
-delete_data(key: str)
-
- -
-
-lock_data(key: str)
-
- -
-
-modify_data(key: str, modified_by: str)
-
- -
-
-restore_data(key: str)
-
- -
-
-synchronise_data(key: str)
-
- -
-
-update([E, ]**F) → None. Update D from dict/iterable E and F.
-

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] -If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v -In either case, this is followed by: for k in F: D[k] = F[k]

-
- -
- -
-
-exception pyminer2.workspace.datamanager.metadataset.WouldBlockError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.recyclebin module

-
-
-class pyminer2.workspace.datamanager.recyclebin.RecycleBin(max_size=1000)
-

基类:list

-
-
-discard(varname: str, variable)
-
- -
-
-get_varname(index: int)
-
- -
-
-restore(index: int, var_to_discard=None) → tuple
-
- -
- -
-
-

pyminer2.workspace.datamanager.variable module

-
-
-class pyminer2.workspace.datamanager.variable.Variable(vartype: str, members: dict)
-

基类:dict

-
-
-dump()
-
- -
-
-dumps()
-
- -
-
-load(dct: dict)
-
- -
-
-loads(jsonstr: str)
-
- -
- -
-
-exception pyminer2.workspace.datamanager.variable.VariableError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.varset module

-
-
-class pyminer2.workspace.datamanager.varset.VarSet
-

基类:dict

-
-
-get_var(varname: str)
-
- -
-
-insert_builtin_types(builtin_types: dict)
-
- -
-
-set_var(varname: str, variable)
-
- -
- -
-
-

Module contents

-
-
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/dts/pyminer2.workspace.html b/docs/_build/html/dts/pyminer2.workspace.html deleted file mode 100644 index 66acbdca4370b371b0b0145b66026a0d88be29c8..0000000000000000000000000000000000000000 --- a/docs/_build/html/dts/pyminer2.workspace.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - - pyminer2.workspace package — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
- -
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html deleted file mode 100644 index 2cb37004ab291e19146908665831486f292a783b..0000000000000000000000000000000000000000 --- a/docs/_build/html/genindex.html +++ /dev/null @@ -1,2343 +0,0 @@ - - - - - - - - - - 索引 — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • 索引
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- - -

索引

- -
- A - | B - | C - | D - | E - | F - | G - | H - | I - | K - | L - | M - | N - | O - | P - | Q - | R - | S - | T - | U - | V - | W - | Y - | - -
-

A

- - - -
- -

B

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

F

- - - -
- -

G

- - - -
- -

H

- - - -
- -

I

- - - -
- -

K

- - -
- -

L

- - - -
- -

M

- - - -
- -

N

- - - -
- -

O

- - - -
- -

P

- - - -
    -
  • - pyminer2.ui - -
  • -
  • - pyminer2.ui.common - -
  • -
  • - pyminer2.ui.common.locale - -
  • -
  • - pyminer2.ui.common.openprocess - -
  • -
  • - pyminer2.ui.common.platformutil - -
  • -
  • - pyminer2.ui.common.test_comm - -
  • -
  • - pyminer2.ui.generalwidgets - -
  • -
  • - pyminer2.ui.generalwidgets.basicwidgets - -
  • -
  • - pyminer2.ui.generalwidgets.basicwidgets.labels - -
  • -
  • - pyminer2.ui.generalwidgets.basicwidgets.object - -
  • -
  • - pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons - -
  • -
  • - pyminer2.ui.generalwidgets.basicwidgets.toolbutton - -
  • -
  • - pyminer2.ui.generalwidgets.browser - -
  • -
  • - pyminer2.ui.generalwidgets.containers - -
  • -
  • - pyminer2.ui.generalwidgets.containers.flowarea - -
  • -
  • - pyminer2.ui.generalwidgets.containers.pmscrollarea - -
  • -
  • - pyminer2.ui.generalwidgets.containers.PMTab - -
  • -
  • - pyminer2.ui.generalwidgets.demos_and_tests - -
  • -
  • - pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo - -
  • -
  • - pyminer2.ui.generalwidgets.layouts - -
  • -
  • - pyminer2.ui.generalwidgets.layouts.flowlayout - -
  • -
  • - pyminer2.ui.generalwidgets.sourcemgr - -
  • -
  • - pyminer2.ui.generalwidgets.sourcemgr.iconutils - -
  • -
  • - pyminer2.ui.generalwidgets.table - -
  • -
  • - pyminer2.ui.generalwidgets.table.tableviews - -
  • -
  • - pyminer2.ui.generalwidgets.table.tablewidgets - -
  • -
  • - pyminer2.ui.generalwidgets.textctrls - -
  • -
  • - pyminer2.ui.generalwidgets.textctrls.highlighter - -
  • -
  • - pyminer2.ui.generalwidgets.textctrls.textctrl - -
  • -
  • - pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow - -
  • -
  • - pyminer2.ui.generalwidgets.toolbars - -
  • -
  • - pyminer2.ui.generalwidgets.toolbars.toolbar - -
  • -
  • - pyminer2.ui.generalwidgets.window - -
  • -
  • - pyminer2.ui.generalwidgets.window.applicationtest - -
  • -
  • - pyminer2.ui.generalwidgets.window.mainwindow_new - -
  • -
  • - pyminer2.ui.generalwidgets.window.pmdockwidget - -
  • -
  • - pyminer2.ui.generalwidgets.window.pmmainwindow - -
  • -
  • - pyminer2.ui.pmwidgets - -
  • -
  • - pyminer2.ui.pmwidgets.toplevel - -
  • -
  • - pyminer2.ui.pyqtsource_rc - -
  • -
  • - pyminer2.ui.source - -
  • -
  • - pyminer2.ui.source.qss - -
  • -
  • - pyminer2.ui.source.qss.qss_tools - -
  • -
  • - pyminer2.workspace - -
  • -
  • - pyminer2.workspace.datamanager - -
  • -
  • - pyminer2.workspace.datamanager.converter - -
  • -
  • - pyminer2.workspace.datamanager.datamanager - -
  • -
  • - pyminer2.workspace.datamanager.dataset - -
  • -
  • - pyminer2.workspace.datamanager.exceptions - -
  • -
  • - pyminer2.workspace.datamanager.historyset - -
  • -
  • - pyminer2.workspace.datamanager.metadataset - -
  • -
  • - pyminer2.workspace.datamanager.recyclebin - -
  • -
  • - pyminer2.workspace.datamanager.variable - -
  • -
  • - pyminer2.workspace.datamanager.varset - -
  • -
  • PythonHighlighter (pyminer2.ui.generalwidgets.textctrls.highlighter 中的类), [1] -
  • -
- -

Q

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - - -
- -

V

- - - -
- -

W

- - - -
- -

Y

- - - -
- -

- - -
- - - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html deleted file mode 100644 index 63b9a588b28fcfd7a3e8087ef1f08b3a2a9268b7..0000000000000000000000000000000000000000 --- a/docs/_build/html/index.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - - - - - - - Welcome to PyMiner’s documentation! — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Welcome to PyMiner’s documentation!
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

Welcome to PyMiner’s documentation!

-

PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。

- -
-

API Reference

-
-

Contents:

- -
-
-
-
-

Indices and tables

- -
- - -
- -
-
- - - - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv deleted file mode 100644 index 4cdb66e2daae8a1f3d0d60217fb4226f2813db6f..0000000000000000000000000000000000000000 Binary files a/docs/_build/html/objects.inv and /dev/null differ diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html deleted file mode 100644 index 5d7e2a07b9fafdeee689f87504468068772868ec..0000000000000000000000000000000000000000 --- a/docs/_build/html/py-modindex.html +++ /dev/null @@ -1,717 +0,0 @@ - - - - - - - - - - Python 模块索引 — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Python 模块索引
  • - - -
  • - -
  • - -
- - -
-
-
-
- - -

Python 模块索引

- -
- p -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- p
- pmgwidgets -
    - pmgwidgets.normal -
    - pmgwidgets.normal.value_inputs -
    - pmgwidgets.table -
    - pmgwidgets.table.tableviews -
    - pmgwidgets.table.tablewidgets -
- pyminer2 -
    - pyminer2.extensions -
    - pyminer2.extensions.extensionlib -
    - pyminer2.extensions.extensionlib.baseext -
    - pyminer2.extensions.extensionlib.extension_lib -
    - pyminer2.extensions.extensionlib.pmext -
    - pyminer2.extensions.extensions_manager -
    - pyminer2.extensions.extensions_manager.ExtensionLoader -
    - pyminer2.extensions.extensions_manager.log -
    - pyminer2.extensions.extensions_manager.manager -
    - pyminer2.extensions.extensions_manager.UIInserter -
    - pyminer2.extensions.package_manager -
    - pyminer2.extensions.package_manager.env_manager -
    - pyminer2.extensions.package_manager.package_install -
    - pyminer2.extensions.package_manager.package_remove -
    - pyminer2.extensions.package_manager.package_setting -
    - pyminer2.extensions.package_manager.package_update -
    - pyminer2.extensions.test_demo -
    - pyminer2.extensions.test_demo.extensionlib -
    - pyminer2.extensions.test_demo.extensions -
    - pyminer2.extensions.test_demo.extensions.test_extension -
    - pyminer2.extensions.test_demo.extensions.test_extension.entry -
    - pyminer2.extensions.test_demo.extensions.test_extension.interface -
    - pyminer2.extensions.test_demo.extensions.test_extension.menu -
    - pyminer2.extensions.test_demo.extensions.test_extension.subwindow -
    - pyminer2.extensions.test_demo.extensions.test_extension2 -
    - pyminer2.extensions.test_demo.extensions.test_extension2.entry -
    - pyminer2.extensions.test_demo.extensions.test_extension2.interface -
    - pyminer2.extensions.test_demo.extensions.test_extension2.menu -
    - pyminer2.extensions.test_demo.extensions.test_extension2.subwindow -
    - pyminer2.extensions.test_demo.mainform -
    - pyminer2.pmutil -
    - pyminer2.ui -
    - pyminer2.ui.common -
    - pyminer2.ui.common.locale -
    - pyminer2.ui.common.openprocess -
    - pyminer2.ui.common.platformutil -
    - pyminer2.ui.common.test_comm -
    - pyminer2.ui.generalwidgets -
    - pyminer2.ui.generalwidgets.basicwidgets -
    - pyminer2.ui.generalwidgets.basicwidgets.labels -
    - pyminer2.ui.generalwidgets.basicwidgets.object -
    - pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons -
    - pyminer2.ui.generalwidgets.basicwidgets.toolbutton -
    - pyminer2.ui.generalwidgets.browser -
    - pyminer2.ui.generalwidgets.containers -
    - pyminer2.ui.generalwidgets.containers.flowarea -
    - pyminer2.ui.generalwidgets.containers.pmscrollarea -
    - pyminer2.ui.generalwidgets.containers.PMTab -
    - pyminer2.ui.generalwidgets.demos_and_tests -
    - pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo -
    - pyminer2.ui.generalwidgets.layouts -
    - pyminer2.ui.generalwidgets.layouts.flowlayout -
    - pyminer2.ui.generalwidgets.sourcemgr -
    - pyminer2.ui.generalwidgets.sourcemgr.iconutils -
    - pyminer2.ui.generalwidgets.table -
    - pyminer2.ui.generalwidgets.table.tableviews -
    - pyminer2.ui.generalwidgets.table.tablewidgets -
    - pyminer2.ui.generalwidgets.textctrls -
    - pyminer2.ui.generalwidgets.textctrls.highlighter -
    - pyminer2.ui.generalwidgets.textctrls.textctrl -
    - pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow -
    - pyminer2.ui.generalwidgets.toolbars -
    - pyminer2.ui.generalwidgets.toolbars.toolbar -
    - pyminer2.ui.generalwidgets.window -
    - pyminer2.ui.generalwidgets.window.applicationtest -
    - pyminer2.ui.generalwidgets.window.mainwindow_new -
    - pyminer2.ui.generalwidgets.window.pmdockwidget -
    - pyminer2.ui.generalwidgets.window.pmmainwindow -
    - pyminer2.ui.pmwidgets -
    - pyminer2.ui.pmwidgets.toplevel -
    - pyminer2.ui.pyqtsource_rc -
    - pyminer2.ui.source -
    - pyminer2.ui.source.qss -
    - pyminer2.ui.source.qss.qss_tools -
    - pyminer2.workspace -
    - pyminer2.workspace.datamanager -
    - pyminer2.workspace.datamanager.converter -
    - pyminer2.workspace.datamanager.datamanager -
    - pyminer2.workspace.datamanager.dataset -
    - pyminer2.workspace.datamanager.exceptions -
    - pyminer2.workspace.datamanager.historyset -
    - pyminer2.workspace.datamanager.metadataset -
    - pyminer2.workspace.datamanager.recyclebin -
    - pyminer2.workspace.datamanager.variable -
    - pyminer2.workspace.datamanager.varset -
- - -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html deleted file mode 100644 index f827aec7a65b08d7052ac06fdba301e0d9d63a03..0000000000000000000000000000000000000000 --- a/docs/_build/html/search.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - - - - - 搜索 — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • 搜索
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- - - - -
- -
- -
- -
-
- - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js deleted file mode 100644 index 95e49825ea6cf0b12ed7d646f20d4d479a4c3de2..0000000000000000000000000000000000000000 --- a/docs/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["dts/app2","dts/modules","dts/pmgwidgets","dts/pmgwidgets.normal","dts/pmgwidgets.table","dts/pyminer2","dts/pyminer2.extensions","dts/pyminer2.extensions.extensionlib","dts/pyminer2.extensions.extensions_manager","dts/pyminer2.extensions.package_manager","dts/pyminer2.extensions.test_demo","dts/pyminer2.extensions.test_demo.extensions","dts/pyminer2.extensions.test_demo.extensions.test_extension","dts/pyminer2.extensions.test_demo.extensions.test_extension2","dts/pyminer2.ui","dts/pyminer2.ui.base","dts/pyminer2.ui.base.widgets","dts/pyminer2.ui.common","dts/pyminer2.ui.generalwidgets","dts/pyminer2.ui.generalwidgets.basicwidgets","dts/pyminer2.ui.generalwidgets.browser","dts/pyminer2.ui.generalwidgets.containers","dts/pyminer2.ui.generalwidgets.demos_and_tests","dts/pyminer2.ui.generalwidgets.layouts","dts/pyminer2.ui.generalwidgets.sourcemgr","dts/pyminer2.ui.generalwidgets.table","dts/pyminer2.ui.generalwidgets.textctrls","dts/pyminer2.ui.generalwidgets.toolbars","dts/pyminer2.ui.generalwidgets.window","dts/pyminer2.ui.pmwidgets","dts/pyminer2.ui.source","dts/pyminer2.ui.source.qss","dts/pyminer2.workspace","dts/pyminer2.workspace.datamanager","index","user/intro","user/joinus","user/lib_ref","user/tech"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,sphinx:56},filenames:["dts/app2.rst","dts/modules.rst","dts/pmgwidgets.rst","dts/pmgwidgets.normal.rst","dts/pmgwidgets.table.rst","dts/pyminer2.rst","dts/pyminer2.extensions.rst","dts/pyminer2.extensions.extensionlib.rst","dts/pyminer2.extensions.extensions_manager.rst","dts/pyminer2.extensions.package_manager.rst","dts/pyminer2.extensions.test_demo.rst","dts/pyminer2.extensions.test_demo.extensions.rst","dts/pyminer2.extensions.test_demo.extensions.test_extension.rst","dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst","dts/pyminer2.ui.rst","dts/pyminer2.ui.base.rst","dts/pyminer2.ui.base.widgets.rst","dts/pyminer2.ui.common.rst","dts/pyminer2.ui.generalwidgets.rst","dts/pyminer2.ui.generalwidgets.basicwidgets.rst","dts/pyminer2.ui.generalwidgets.browser.rst","dts/pyminer2.ui.generalwidgets.containers.rst","dts/pyminer2.ui.generalwidgets.demos_and_tests.rst","dts/pyminer2.ui.generalwidgets.layouts.rst","dts/pyminer2.ui.generalwidgets.sourcemgr.rst","dts/pyminer2.ui.generalwidgets.table.rst","dts/pyminer2.ui.generalwidgets.textctrls.rst","dts/pyminer2.ui.generalwidgets.toolbars.rst","dts/pyminer2.ui.generalwidgets.window.rst","dts/pyminer2.ui.pmwidgets.rst","dts/pyminer2.ui.source.rst","dts/pyminer2.ui.source.qss.rst","dts/pyminer2.workspace.rst","dts/pyminer2.workspace.datamanager.rst","index.rst","user/intro.rst","user/joinus.rst","user/lib_ref.rst","user/tech.rst"],objects:{"":{pmgwidgets:[37,0,0,"-"],pyminer2:[37,0,0,"-"]},"pmgwidgets.normal":{value_inputs:[37,0,0,"-"]},"pmgwidgets.normal.value_inputs":{AnyType:[37,1,1,""],BaseParamWidget:[37,1,1,""],Check:[37,1,1,""],Choice:[37,1,1,""],Choices:[37,1,1,""],ColorCtrl:[37,1,1,""],FloatSlider:[37,1,1,""],Label:[37,1,1,""],NumCtrl:[37,1,1,""],PathCtrl:[37,1,1,""],SettingsPanel:[37,1,1,""],TextCtrl:[37,1,1,""]},"pmgwidgets.normal.value_inputs.AnyType":{Bind:[37,2,1,""],get_value:[37,2,1,""],on_text:[37,2,1,""],on_type:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.BaseParamWidget":{get_value:[37,2,1,""],is_key:[37,2,1,""],para_changed:[37,2,1,""],set_app:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.Check":{get_value:[37,2,1,""],on_check:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.Choice":{get_value:[37,2,1,""],on_choice:[37,2,1,""],on_radio_button_toggled:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.Choices":{Bind:[37,2,1,""],get_value:[37,2,1,""],on_check:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.ColorCtrl":{Bind:[37,2,1,""],colorStr2Tup:[37,2,1,""],colorTup2Str:[37,2,1,""],get_value:[37,2,1,""],oncolor:[37,2,1,""],ontext:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.FloatSlider":{Bind:[37,2,1,""],get_value:[37,2,1,""],on_scroll:[37,2,1,""],on_spin:[37,2,1,""],on_text:[37,2,1,""],set_para:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.Label":{Bind:[37,2,1,""],get_value:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.NumCtrl":{Bind:[37,2,1,""],Refresh:[37,2,1,""],f:[37,2,1,""],get_value:[37,2,1,""],ontext:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.PathCtrl":{get_value:[37,2,1,""],onselect:[37,2,1,""],ontext:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.normal.value_inputs.SettingsPanel":{closeEvent:[37,2,1,""],get_value:[37,2,1,""],widgets_dic:[37,3,1,""]},"pmgwidgets.normal.value_inputs.TextCtrl":{Bind:[37,2,1,""],get_value:[37,2,1,""],ontext:[37,2,1,""],param_changed:[37,2,1,""],set_value:[37,2,1,""]},"pmgwidgets.table":{tableviews:[37,0,0,"-"],tablewidgets:[37,0,0,"-"]},"pmgwidgets.table.tableviews":{PMTableView:[37,1,1,""],TableModelForList:[37,1,1,""],TableModelForNumpyArray:[37,1,1,""],TableModelForPandasDataframe:[37,1,1,""],dataformat:[37,4,1,""],to_decimal_str:[37,4,1,""]},"pmgwidgets.table.tableviews.PMTableView":{set_data:[37,2,1,""]},"pmgwidgets.table.tableviews.TableModelForList":{columnCount:[37,2,1,""],data:[37,2,1,""],rowCount:[37,2,1,""]},"pmgwidgets.table.tableviews.TableModelForNumpyArray":{columnCount:[37,2,1,""],data:[37,2,1,""],rowCount:[37,2,1,""]},"pmgwidgets.table.tableviews.TableModelForPandasDataframe":{columnCount:[37,2,1,""],data:[37,2,1,""],headerData:[37,2,1,""],rowCount:[37,2,1,""]},"pmgwidgets.table.tablewidgets":{PMGTableTabWidget:[37,1,1,""],PMGTableWidget:[37,1,1,""]},"pmgwidgets.table.tablewidgets.PMGTableWidget":{check_data_can_be_displayed_by_table:[37,2,1,""],closeEvent:[37,2,1,""],data_name:[37,3,1,""],data_shown:[37,3,1,""],set_data_2d:[37,2,1,""]},"pyminer2.extensions":{extensionlib:[37,0,0,"-"],extensions_manager:[37,0,0,"-"],package_manager:[37,0,0,"-"],test_demo:[37,0,0,"-"]},"pyminer2.extensions.extensionlib":{baseext:[37,0,0,"-"],extension_lib:[37,0,0,"-"],pmext:[37,0,0,"-"]},"pyminer2.extensions.extensionlib.baseext":{BaseExtension:[37,1,1,""],BaseInterface:[37,1,1,""]},"pyminer2.extensions.extensionlib.baseext.BaseExtension":{extension_lib:[37,3,1,""],get_widget:[37,2,1,""],public_interface:[37,3,1,""],widget_classes:[37,3,1,""],widgets:[37,3,1,""]},"pyminer2.extensions.extensionlib.baseext.BaseInterface":{hello:[37,2,1,""]},"pyminer2.extensions.extensionlib.extension_lib":{wrapper:[37,4,1,""]},"pyminer2.extensions.extensionlib.pmext":{PluginInterface:[37,1,1,""]},"pyminer2.extensions.extensionlib.pmext.PluginInterface":{Signals:[37,1,1,""],add_docked_widget:[37,2,1,""],add_tool_bar:[37,2,1,""],append_to_context_menu:[37,2,1,""],append_to_sidebar:[37,2,1,""],append_to_toolbar:[37,2,1,""],append_to_toolbox:[37,2,1,""],append_to_tray_menu:[37,2,1,""],append_widget_to_toolbar:[37,2,1,""],get_console:[37,2,1,""],get_data_manager:[37,2,1,""],get_dialog_class:[37,2,1,""],get_editor:[37,2,1,""],get_root_dir:[37,2,1,""],get_toolbar:[37,2,1,""],get_toolbar_widget:[37,2,1,""],get_work_dir:[37,2,1,""],get_workspace_inspector:[37,2,1,""],set_work_dir:[37,2,1,""],show_dialog:[37,2,1,""],show_log:[37,2,1,""],show_tool_bar:[37,2,1,""],switch_tool_bar:[37,2,1,""]},"pyminer2.extensions.extensionlib.pmext.PluginInterface.Signals":{get_main_window_close_signal:[37,2,1,""]},"pyminer2.extensions.extensions_manager":{ExtensionLoader:[37,0,0,"-"],UIInserter:[37,0,0,"-"],log:[37,0,0,"-"],manager:[37,0,0,"-"]},"pyminer2.extensions.extensions_manager.ExtensionLoader":{ExtensionLoader:[37,1,1,""],Info:[37,1,1,""],PublicInterface:[37,1,1,""]},"pyminer2.extensions.extensions_manager.ExtensionLoader.ExtensionLoader":{binding_info:[37,2,1,""],create_public_interface:[37,2,1,""],import_module:[37,2,1,""],load:[37,2,1,""],load_class:[37,2,1,""],load_widget:[37,2,1,""],reset:[37,2,1,""]},"pyminer2.extensions.extensions_manager.ExtensionLoader.Info":{description:[37,2,1,""],display_name:[37,2,1,""],icon:[37,2,1,""],name:[37,2,1,""],path:[37,2,1,""],version:[37,2,1,""]},"pyminer2.extensions.extensions_manager.UIInserter":{UiInserter:[37,1,1,""],get_dock_by_position:[37,4,1,""],get_item_coor:[37,4,1,""]},"pyminer2.extensions.extensions_manager.UIInserter.UiInserter":{append_to_toolbar:[37,2,1,""],new_dock_window:[37,2,1,""],new_toolbar:[37,2,1,""]},"pyminer2.extensions.extensions_manager.log":{assert_:[37,4,1,""],error:[37,4,1,""],log:[37,4,1,""]},"pyminer2.extensions.extensions_manager.manager":{ExtensionsManager:[37,1,1,""]},"pyminer2.extensions.extensions_manager.manager.ExtensionsManager":{get_ext_by_id:[37,2,1,""],get_ext_by_name:[37,2,1,""],install:[37,2,1,""],install_web:[37,2,1,""],load:[37,2,1,""],load_one:[37,2,1,""],uninstall:[37,2,1,""]},"pyminer2.extensions.package_manager":{env_manager:[37,0,0,"-"],package_install:[37,0,0,"-"],package_remove:[37,0,0,"-"],package_setting:[37,0,0,"-"],package_update:[37,0,0,"-"]},"pyminer2.extensions.package_manager.env_manager":{Ui_Form:[37,1,1,""]},"pyminer2.extensions.package_manager.env_manager.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.extensions.package_manager.package_install":{Ui_Form:[37,1,1,""]},"pyminer2.extensions.package_manager.package_install.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.extensions.package_manager.package_remove":{Ui_Form:[37,1,1,""]},"pyminer2.extensions.package_manager.package_remove.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.extensions.package_manager.package_setting":{Ui_Form:[37,1,1,""]},"pyminer2.extensions.package_manager.package_setting.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.extensions.package_manager.package_update":{Ui_Form:[37,1,1,""]},"pyminer2.extensions.package_manager.package_update.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.extensions.test_demo":{extensionlib:[37,0,0,"-"],extensions:[37,0,0,"-"],mainform:[37,0,0,"-"]},"pyminer2.extensions.test_demo.extensionlib":{DataClient:[37,1,1,""],Entry:[37,1,1,""],Menu:[37,1,1,""],SubWindow:[37,1,1,""]},"pyminer2.extensions.test_demo.extensionlib.DataClient":{lock:[37,2,1,""],read:[37,2,1,""],read_and_write:[37,2,1,""],unlock:[37,2,1,""],write:[37,2,1,""]},"pyminer2.extensions.test_demo.extensionlib.Entry":{get_dependency_interface:[37,2,1,""],get_interface:[37,2,1,""],run:[37,2,1,""],start_menu:[37,2,1,""],start_subWindow:[37,2,1,""]},"pyminer2.extensions.test_demo.extensionlib.Menu":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.extensionlib.SubWindow":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions":{test_extension2:[37,0,0,"-"],test_extension:[37,0,0,"-"]},"pyminer2.extensions.test_demo.extensions.test_extension":{"interface":[37,0,0,"-"],entry:[37,0,0,"-"],menu:[37,0,0,"-"],subwindow:[37,0,0,"-"]},"pyminer2.extensions.test_demo.extensions.test_extension.entry":{MyEntry:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.entry.MyEntry":{run:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.interface":{MyInterface:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.interface.MyInterface":{method:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.menu":{MyMenu:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.subwindow":{MySubWindow1:[37,1,1,""],MySubWindow2:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow1":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow2":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2":{"interface":[37,0,0,"-"],entry:[37,0,0,"-"],menu:[37,0,0,"-"],subwindow:[37,0,0,"-"]},"pyminer2.extensions.test_demo.extensions.test_extension2.entry":{YourEntry:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.entry.YourEntry":{run:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.interface":{YourInterface:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.interface.YourInterface":{method:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.menu":{YourMenu:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.subwindow":{YourSubWindow1:[37,1,1,""],YourSubWindow2:[37,1,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow1":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow2":{test:[37,2,1,""]},"pyminer2.extensions.test_demo.mainform":{Extension:[37,1,1,""],MainForm:[37,1,1,""],main:[37,4,1,""]},"pyminer2.extensions.test_demo.mainform.Extension":{dynamic_binding:[37,2,1,""],end:[37,2,1,""],get_interface:[37,2,1,""],import_module:[37,2,1,""],life_period:[37,2,1,""],start:[37,2,1,""],start_menu:[37,2,1,""],start_subwindow:[37,2,1,""],wrap_interface:[37,2,1,""]},"pyminer2.extensions.test_demo.mainform.MainForm":{end_extension:[37,2,1,""],flush:[37,2,1,""],get_dependency_interface:[37,2,1,""],load_extension:[37,2,1,""],run_extension:[37,2,1,""],start_extension:[37,2,1,""],start_menu:[37,2,1,""],start_subwindow:[37,2,1,""]},"pyminer2.pmutil":{get_application:[37,4,1,""],get_main_window:[37,4,1,""],get_root_dir:[37,4,1,""],get_work_dir:[37,4,1,""]},"pyminer2.ui":{common:[37,0,0,"-"],generalwidgets:[37,0,0,"-"],pmwidgets:[37,0,0,"-"],pyqtsource_rc:[37,0,0,"-"],source:[37,0,0,"-"]},"pyminer2.ui.common":{locale:[37,0,0,"-"],openprocess:[37,0,0,"-"],platformutil:[37,0,0,"-"],test_comm:[37,0,0,"-"]},"pyminer2.ui.common.locale":{Locale:[37,1,1,""]},"pyminer2.ui.common.locale.Locale":{add_locale:[37,2,1,""],locale:[37,3,1,""],translate:[37,2,1,""],translations:[37,3,1,""],valid_locales:[37,3,1,""]},"pyminer2.ui.common.openprocess":{PMProcess:[37,1,1,""]},"pyminer2.ui.common.openprocess.PMProcess":{consoleLoop:[37,2,1,""],enqueue_stream:[37,2,1,""]},"pyminer2.ui.common.platformutil":{check_platform:[37,4,1,""],run_command_in_terminal:[37,4,1,""]},"pyminer2.ui.generalwidgets":{basicwidgets:[37,0,0,"-"],browser:[37,0,0,"-"],containers:[37,0,0,"-"],demos_and_tests:[37,0,0,"-"],layouts:[37,0,0,"-"],sourcemgr:[37,0,0,"-"],table:[37,0,0,"-"],textctrls:[37,0,0,"-"],toolbars:[37,0,0,"-"],window:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.basicwidgets":{labels:[37,0,0,"-"],object:[37,0,0,"-"],pmpushbuttons:[37,0,0,"-"],toolbutton:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.basicwidgets.labels":{PMScrollableLabel:[37,1,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.object":{PMDockObject:[37,1,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.object.PMDockObject":{on_closed_action:[37,3,1,""],on_dock_widget_deleted:[37,2,1,""],raise_widget_to_visible:[37,2,1,""],signal_raise_into_view:[37,3,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons":{PMPushButtonPane:[37,1,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons.PMPushButtonPane":{add_button:[37,2,1,""],add_buttons:[37,2,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.toolbutton":{PMToolButton:[37,1,1,""]},"pyminer2.ui.generalwidgets.basicwidgets.toolbutton.PMToolButton":{set_btn_clicked_effect:[37,2,1,""],shadow:[37,3,1,""],unset_btn_clicked_effect:[37,2,1,""]},"pyminer2.ui.generalwidgets.containers":{PMTab:[37,0,0,"-"],flowarea:[37,0,0,"-"],pmscrollarea:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.containers.PMTab":{PMTabWidget:[37,1,1,""]},"pyminer2.ui.generalwidgets.containers.PMTab.PMTabWidget":{addScrolledAreaTab:[37,2,1,""],setup_ui:[37,2,1,""]},"pyminer2.ui.generalwidgets.containers.flowarea":{PMFlowArea:[37,1,1,""],PMFlowAreaWidget:[37,1,1,""]},"pyminer2.ui.generalwidgets.containers.flowarea.PMFlowArea":{add_tool_button:[37,2,1,""],add_widget:[37,2,1,""],set_layout_content_margins:[37,2,1,""],setup_ui:[37,2,1,""]},"pyminer2.ui.generalwidgets.containers.flowarea.PMFlowAreaWidget":{add_widget:[37,2,1,""],resizeEvent:[37,2,1,""],setup_ui:[37,2,1,""]},"pyminer2.ui.generalwidgets.containers.pmscrollarea":{PMScrollArea:[37,1,1,""]},"pyminer2.ui.generalwidgets.containers.pmscrollarea.PMScrollArea":{setup_ui:[37,2,1,""]},"pyminer2.ui.generalwidgets.demos_and_tests":{qmenu_demo:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo":{Demo:[37,1,1,""]},"pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo.Demo":{A:[37,2,1,""],B:[37,2,1,""]},"pyminer2.ui.generalwidgets.layouts":{flowlayout:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.layouts.flowlayout":{PMFlowLayout:[37,1,1,""],PMFlowLayoutWithGrid:[37,1,1,""]},"pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayout":{add_widget:[37,2,1,""],on_resize:[37,2,1,""]},"pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayoutWithGrid":{addWidget:[37,2,1,""],on_resize:[37,2,1,""]},"pyminer2.ui.generalwidgets.sourcemgr":{iconutils:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.sourcemgr.iconutils":{create_icon:[37,4,1,""]},"pyminer2.ui.generalwidgets.table":{tableviews:[37,0,0,"-"],tablewidgets:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.table.tableviews":{PMTableView:[37,1,1,""],TableModelForList:[37,1,1,""],TableModelForNumpyArray:[37,1,1,""],TableModelForPandasDataframe:[37,1,1,""],dataformat:[37,4,1,""]},"pyminer2.ui.generalwidgets.table.tableviews.PMTableView":{set_data:[37,2,1,""]},"pyminer2.ui.generalwidgets.table.tableviews.TableModelForList":{columnCount:[37,2,1,""],data:[37,2,1,""],rowCount:[37,2,1,""]},"pyminer2.ui.generalwidgets.table.tableviews.TableModelForNumpyArray":{columnCount:[37,2,1,""],data:[37,2,1,""],rowCount:[37,2,1,""]},"pyminer2.ui.generalwidgets.table.tableviews.TableModelForPandasDataframe":{columnCount:[37,2,1,""],data:[37,2,1,""],headerData:[37,2,1,""],rowCount:[37,2,1,""]},"pyminer2.ui.generalwidgets.table.tablewidgets":{PMGTableTabWidget:[37,1,1,""],PMGTableWidget:[37,1,1,""]},"pyminer2.ui.generalwidgets.table.tablewidgets.PMGTableWidget":{check_data_can_be_displayed_by_table:[37,2,1,""],closeEvent:[37,2,1,""],data_name:[37,3,1,""],data_shown:[37,3,1,""],set_data_2d:[37,2,1,""]},"pyminer2.ui.generalwidgets.textctrls":{highlighter:[37,0,0,"-"],textctrl:[37,0,0,"-"],textwidgetlineshow:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.textctrls.highlighter":{PythonHighlighter:[37,1,1,""]},"pyminer2.ui.generalwidgets.textctrls.highlighter.PythonHighlighter":{Formats:[37,3,1,""],Rules:[37,3,1,""],highlightBlock:[37,2,1,""],initializeFormats:[37,2,1,""],rehighlight:[37,2,1,""]},"pyminer2.ui.generalwidgets.textctrls.textctrl":{PMGCodeEdit:[37,1,1,""]},"pyminer2.ui.generalwidgets.textctrls.textctrl.PMGCodeEdit":{autocomp_show:[37,2,1,""],comment:[37,2,1,""],editIndent:[37,2,1,""],editUnindent:[37,2,1,""],hide_autocomp:[37,2,1,""],keyPressEvent:[37,2,1,""],on_back_tab:[37,2,1,""],on_backspace:[37,2,1,""],on_close_request:[37,2,1,""],on_return_pressed:[37,2,1,""],on_tab:[37,2,1,""],on_text_changed:[37,2,1,""],save:[37,2,1,""],signal_save:[37,3,1,""],updateUi:[37,2,1,""]},"pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow":{PMEditorWithLineNumber:[37,1,1,""],QLineNumberArea:[37,1,1,""]},"pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.PMEditorWithLineNumber":{highlightCurrentLine:[37,2,1,""],keyPressEvent:[37,2,1,""],lineNumberAreaPaintEvent:[37,2,1,""],lineNumberAreaWidth:[37,2,1,""],mousePressEvent:[37,2,1,""],on_scroll:[37,2,1,""],resizeEvent:[37,2,1,""],updateLineNumberArea:[37,2,1,""],updateLineNumberAreaWidth:[37,2,1,""],wheelEvent:[37,2,1,""]},"pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.QLineNumberArea":{paintEvent:[37,2,1,""],sizeHint:[37,2,1,""]},"pyminer2.ui.generalwidgets.toolbars":{toolbar:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.toolbars.toolbar":{ActionWithMessage:[37,1,1,""],PMToolBar:[37,1,1,""],TopToolBar:[37,1,1,""]},"pyminer2.ui.generalwidgets.toolbars.toolbar.PMToolBar":{add_buttons:[37,2,1,""],add_menu_to:[37,2,1,""],add_tool_button:[37,2,1,""],add_widget:[37,2,1,""],get_control_widget:[37,2,1,""],tab_button:[37,3,1,""]},"pyminer2.ui.generalwidgets.toolbars.toolbar.TopToolBar":{add_button:[37,2,1,""],get_button:[37,2,1,""]},"pyminer2.ui.generalwidgets.window":{applicationtest:[37,0,0,"-"],mainwindow_new:[37,0,0,"-"],pmdockwidget:[37,0,0,"-"],pmmainwindow:[37,0,0,"-"]},"pyminer2.ui.generalwidgets.window.applicationtest":{MainWindow:[37,1,1,""],Ui_Form:[37,1,1,""]},"pyminer2.ui.generalwidgets.window.applicationtest.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.ui.generalwidgets.window.mainwindow_new":{MainWindow:[37,1,1,""],Ui_Form:[37,1,1,""]},"pyminer2.ui.generalwidgets.window.mainwindow_new.Ui_Form":{retranslateUi:[37,2,1,""],setupUi:[37,2,1,""]},"pyminer2.ui.generalwidgets.window.pmdockwidget":{PMDockWidget:[37,1,1,""],PMGDockWidget:[37,1,1,""]},"pyminer2.ui.generalwidgets.window.pmdockwidget.PMDockWidget":{closeEvent:[37,2,1,""],raise_into_view:[37,2,1,""]},"pyminer2.ui.generalwidgets.window.pmmainwindow":{BaseMainWindow:[37,1,1,""]},"pyminer2.ui.generalwidgets.window.pmmainwindow.BaseMainWindow":{add_widget_on_dock:[37,2,1,""],bind_events:[37,2,1,""],delete_dock_widget:[37,2,1,""],dialog_classes:[37,3,1,""],dock_places:[37,3,1,""],dock_widgets:[37,3,1,""],get_dock_widget:[37,2,1,""],init_toolbar_tab:[37,2,1,""],load_layout:[37,2,1,""],load_predefined_layout:[37,2,1,""],load_settings:[37,2,1,""],on_boot_finished:[37,2,1,""],raise_dock_into_view:[37,2,1,""],refresh_toolbar_appearance:[37,2,1,""],refresh_view_configs:[37,2,1,""],save_layout:[37,2,1,""],save_settings:[37,2,1,""],settings:[37,3,1,""],show_toolbar:[37,2,1,""],switch_toolbar:[37,2,1,""],toolbars:[37,3,1,""]},"pyminer2.ui.pmwidgets":{toplevel:[37,0,0,"-"]},"pyminer2.ui.pmwidgets.toplevel":{TopLevelWidget:[37,1,1,""]},"pyminer2.ui.pmwidgets.toplevel.TopLevelWidget":{refresh_position:[37,2,1,""],set_central_widget:[37,2,1,""],set_position:[37,2,1,""],set_width:[37,2,1,""]},"pyminer2.ui.pyqtsource_rc":{qCleanupResources:[37,4,1,""],qInitResources:[37,4,1,""]},"pyminer2.ui.source":{qss:[37,0,0,"-"]},"pyminer2.ui.source.qss":{qss_tools:[37,0,0,"-"]},"pyminer2.ui.source.qss.qss_tools":{QssTools:[37,1,1,""]},"pyminer2.ui.source.qss.qss_tools.QssTools":{set_qss_to_obj:[37,2,1,""]},"pyminer2.workspace":{datamanager:[37,0,0,"-"]},"pyminer2.workspace.datamanager":{converter:[37,0,0,"-"],datamanager:[37,0,0,"-"],dataset:[37,0,0,"-"],exceptions:[37,0,0,"-"],historyset:[37,0,0,"-"],metadataset:[37,0,0,"-"],recyclebin:[37,0,0,"-"],variable:[37,0,0,"-"],varset:[37,0,0,"-"]},"pyminer2.workspace.datamanager.converter":{Converter:[37,1,1,""],ConverterError:[37,5,1,""],main:[37,4,1,""]},"pyminer2.workspace.datamanager.converter.Converter":{convert_dataframe:[37,2,1,""],convert_list:[37,2,1,""],convert_ndarray:[37,2,1,""],convert_to_data:[37,2,1,""],convert_to_var:[37,2,1,""],iconvert_dataframe:[37,2,1,""],iconvert_matrix:[37,2,1,""],iconvert_vector:[37,2,1,""]},"pyminer2.workspace.datamanager.datamanager":{DataManager:[37,1,1,""],main:[37,4,1,""]},"pyminer2.workspace.datamanager.datamanager.DataManager":{add_callbacks:[37,2,1,""],cancel:[37,2,1,""],delete_data:[37,2,1,""],get_all_var:[37,2,1,""],get_data_info:[37,2,1,""],get_recyclebin:[37,2,1,""],get_var:[37,2,1,""],lock_data:[37,2,1,""],on_deletion:[37,2,1,""],on_modification:[37,2,1,""],read_data:[37,2,1,""],redo:[37,2,1,""],restore:[37,2,1,""],set_var:[37,2,1,""],set_var_dict:[37,2,1,""],update_data_info:[37,2,1,""],write_data:[37,2,1,""]},"pyminer2.workspace.datamanager.dataset":{DataSet:[37,1,1,""],main:[37,4,1,""]},"pyminer2.workspace.datamanager.dataset.DataSet":{compare:[37,2,1,""],is_valid:[37,2,1,""],read:[37,2,1,""],select_type:[37,2,1,""],synchronise:[37,2,1,""],write:[37,2,1,""]},"pyminer2.workspace.datamanager.exceptions":{ConflictError:[37,5,1,""],NotFoundError:[37,5,1,""]},"pyminer2.workspace.datamanager.historyset":{DataHistory:[37,1,1,""],HistoryError:[37,5,1,""],HistorySet:[37,1,1,""]},"pyminer2.workspace.datamanager.historyset.DataHistory":{push:[37,2,1,""],stepback:[37,2,1,""],stepforward:[37,2,1,""]},"pyminer2.workspace.datamanager.historyset.HistorySet":{push:[37,2,1,""],stepback:[37,2,1,""],stepforward:[37,2,1,""]},"pyminer2.workspace.datamanager.metadataset":{MetaData:[37,1,1,""],MetaDataSet:[37,1,1,""],WouldBlockError:[37,5,1,""]},"pyminer2.workspace.datamanager.metadataset.MetaDataSet":{define_data:[37,2,1,""],delete_data:[37,2,1,""],lock_data:[37,2,1,""],modify_data:[37,2,1,""],restore_data:[37,2,1,""],synchronise_data:[37,2,1,""],update:[37,2,1,""]},"pyminer2.workspace.datamanager.recyclebin":{RecycleBin:[37,1,1,""]},"pyminer2.workspace.datamanager.recyclebin.RecycleBin":{discard:[37,2,1,""],get_varname:[37,2,1,""],restore:[37,2,1,""]},"pyminer2.workspace.datamanager.variable":{Variable:[37,1,1,""],VariableError:[37,5,1,""]},"pyminer2.workspace.datamanager.variable.Variable":{dump:[37,2,1,""],dumps:[37,2,1,""],load:[37,2,1,""],loads:[37,2,1,""]},"pyminer2.workspace.datamanager.varset":{VarSet:[37,1,1,""]},"pyminer2.workspace.datamanager.varset.VarSet":{get_var:[37,2,1,""],insert_builtin_types:[37,2,1,""],set_var:[37,2,1,""]},pmgwidgets:{normal:[37,0,0,"-"],table:[37,0,0,"-"]},pyminer2:{extensions:[37,0,0,"-"],pmutil:[37,0,0,"-"],ui:[37,0,0,"-"],workspace:[37,0,0,"-"]}},objnames:{"0":["py","module","Python \u6a21\u5757"],"1":["py","class","Python \u7c7b"],"2":["py","method","Python \u65b9\u6cd5"],"3":["py","attribute","Python \u5c5e\u6027"],"4":["py","function","Python \u51fd\u6570"],"5":["py","exception","Python \u4f8b\u5916"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function","5":"py:exception"},terms:{"08":[7,37],"10":[7,37,38],"100":[23,37],"1000":[4,25,33,37],"1026801187":36,"1131420577":36,"14":[19,37],"15":[33,37,38],"2020":[7,37],"205591506":36,"23":[7,37],"26":[3,37],"29":[7,37],"30":[19,37],"43":[7,37],"605160230":36,"689417488":36,"827058366":36,"907932713":36,"915736652":36,"945391275":36,"boolean":[8,37],"case":[33,37],"class":[3,4,7,8,9,10,12,13,17,19,21,22,23,25,26,27,28,29,31,33,37],"do":[3,10,37],"float":[3,37],"for":[8,10,33,37],"function":[10,37],"if":[33,37],"in":[10,33,37],"int":[3,4,7,19,21,23,25,27,29,33,37],"new":[24,37],"return":[4,5,7,21,23,25,26,28,37],"static":[4,7,25,26,37],"true":[3,37],"var":[33,37],"with":[10,37],a1:[21,37],aboutm:[5,14,34],accuri:[3,37],action:[22,37],action_command:[27,37],action_text:[27,37],actionwithmessag:[27,37],add_button:[19,27,37],add_callback:[33,37],add_docked_widget:[7,37],add_local:[17,37],add_menu_to:[27,37],add_tool_bar:[7,37],add_tool_button:[21,27,37],add_widget:[21,23,27,37],add_widget_on_dock:[28,37],addscrolledareatab:[21,37],addwidget:[23,37],alia:[8,37],alpha:[3,37],and:[10,33,37],ani:[4,25,37],anytyp:[3,37],app2:[1,34],app:[3,37],append_to_context_menu:[7,37],append_to_sidebar:[7,37],append_to_toolbar:[7,8,37],append_to_toolbox:[7,37],append_to_tray_menu:[7,37],append_widget_to_toolbar:[7,37],applicationtest:[14,18,34],arg:[4,7,17,25,37],arr:[33,37],arrai:[4,25,37],assert_:[8,37],autocomp_show:[26,37],base:[5,14,34],baseext:[5,6,34],baseextens:[7,37],baseinterfac:[7,37],basemainwindow:[28,37],baseparamwidget:[3,37],basicwidget:[14,18,34],be:[10,37],bind:[3,37],bind_ev:[28,37],binding_info:[8,37],bool:[3,4,8,25,33,37],bottom:[28,37],brief:34,browser:[14,18,34],builtin_typ:[33,37],button_nam:[27,37],button_num:[19,27,37],by:[33,37],call:[10,37],callabl:[7,27,37],can:[10,37],cancel:[33,37],cell_data:[4,37],check:[3,37],check_data_can_be_displayed_by_t:[4,25,37],check_platform:[17,37],choic:[3,37],class_nam:[8,37],classmethod:[31,37],close_mod:[17,37],closeev:[3,4,25,28,37],cmd:[17,37],code_editor:[8,37],codeeditor:[7,37],color:[3,37],colorctrl:[3,37],colorstr2tup:[3,37],colortup2str:[3,37],column:[4,23,25,37],column_width:[23,37],columncount:[4,25,37],columnspan:[23,37],com:35,command:[7,37],comment:[26,37],common:[5,14,34],compar:[33,37],complet:[26,37],config:[8,10,12,13,28,37],conflicterror:[33,37],consoleloop:[17,37],consolewidget:[7,14,15,34],contain:[10,14,18,34],content:[1,34],contribut:34,controlpanel:[14,15,34],convert:[5,32,34],convert_datafram:[33,37],convert_list:[33,37],convert_ndarrai:[33,37],convert_to_data:[33,37],convert_to_var:[33,37],convertererror:[33,37],coor:[8,37],core:[33,37],correspond:[10,37],creat:[10,37],create_icon:[24,37],create_public_interfac:[8,37],custom:[28,37],cut:34,cython:[4,25,37],data:[4,10,25,33,37],data_manag:[33,37],data_nam:[4,25,37],data_shown:[4,25,37],datacli:[10,37],dataformat:[4,25,37],datafram:[4,25,33,37],datahistori:[33,37],datamanag:[5,7,32,34],dataset:[5,32,34],dct:[33,37],decim:[4,25,37],define_data:[33,37],delete_data:[33,37],delete_dock_widget:[28,37],deletion_callback:[33,37],demo:[22,37],demos_and_test:[14,18,34],deriv:[3,37],descript:[8,37],develop:[34,35],dialog_class:[28,37],dialog_nam:[7,37],dict:[3,7,8,10,12,13,17,28,33,37],digit:[3,37],dir:[3,37],discard:[33,37],display_nam:[8,37],displayrol:[4,25,37],dock_nam:[7,28,37],dock_plac:[28,37],dock_widget:[28,37],dockwidget:[8,37],doe:[33,37],down:[21,37],dump:[33,37],dy:[26,37],dynamic_bind:[10,37],editind:[26,37],editor:[26,37],editunind:[26,37],either:[33,37],en:[17,37],end:[10,37],end_extens:[10,37],enqueue_stream:[17,37],entri:[3,10,11,34],env_manag:[5,6,34],environ:34,error:[8,37],event:[3,26,37],except:[5,32,34],exchang:[10,37],extens:[1,5,34],extension_lib:[5,6,34],extension_nam:[10,37],extension_packag:[10,37],extensionlib:[5,6,12,13,34],extensionload:[5,6,34],extensions_manag:[5,6,34],extensionsmanag:[8,37],fals:[4,8,25,37],field:[8,37],file:[8,37],file_path:[31,37],filt:[3,37],floatslid:[3,37],flow:[5,14,34],flowarea:[14,18,34],flowlayout:[14,18,34],flowwidget:[14,15,34],flush:[10,37],follow:[33,37],font_siz:[19,37],form:[9,28,37],format:[26,37],frame:[33,37],from:[3,33,37],generalwidget:[5,14,34],get:[10,37],get_all_var:[33,37],get_appl:[5,37],get_button:[27,37],get_consol:[7,37],get_control_widget:[27,37],get_data_info:[33,37],get_data_manag:[7,37],get_dependency_interfac:[10,37],get_dialog_class:[7,37],get_dock_by_posit:[8,37],get_dock_widget:[28,37],get_editor:[7,37],get_ext_by_id:[8,37],get_ext_by_nam:[8,37],get_interfac:[10,37],get_item_coor:[8,37],get_main_window:[5,37],get_main_window_close_sign:[7,37],get_recyclebin:[33,37],get_root_dir:[5,7,37],get_toolbar:[7,37],get_toolbar_widget:[7,37],get_valu:[3,37],get_var:[33,37],get_varnam:[33,37],get_widget:[7,37],get_work_dir:[5,7,37],get_workspace_inspector:[7,37],gpl:35,grid:[23,37],group:34,has:[33,37],headerdata:[4,25,37],height:[19,37],hello:[7,37],hex:[3,37],hide:[19,37],hide_autocomp:[26,37],highlight:[14,18,34],highlightblock:[26,37],highlightcurrentlin:[26,37],historyerror:[33,37],historyset:[5,32,34],how:34,hzy:[7,37],icon:[7,8,19,27,37],icon_path:[7,19,21,24,37],icons_path:[27,37],iconutil:[14,18,34],iconvert_datafram:[33,37],iconvert_matrix:[33,37],iconvert_vector:[33,37],id:[8,37],id_:[8,37],ight:[8,37],imag:[24,37],implement:[10,37],import_modul:[8,10,37],index:[33,37],info:[7,8,10,33,37],info_dict:[33,37],ini:[28,37],init_toolbar_tab:[28,37],initial_column:[23,37],initial_valu:[3,37],initializeformat:[26,37],insert_builtin_typ:[33,37],instal:[8,34,37],install_web:[8,37],instanc:[10,37],interfac:[8,10,11,34],introduct:34,is:[33,37],is_kei:[3,37],is_valid:[33,37],it:[10,37],itemdatarol:[4,25,37],iter:[33,37],its:[10,37],join:34,json:[8,10,37],jsonstr:[33,37],jupyt:[7,37],kei:[33,37],key_backspace_ev:[26,37],keypressev:[26,37],label:[3,14,18,34],lack:[33,37],layout:[14,18,28,34],layout_typ:[28,37],left:[7,8,21,28,37],level:[7,37],licens:34,life_period:[10,37],like:[3,37],linenumberareapaintev:[26,37],linenumberareawidth:[26,37],linux:38,list:[3,4,17,19,25,26,27,33,37],load:[8,33,37],load_class:[8,37],load_extens:[10,37],load_layout:[28,37],load_on:[8,37],load_predefined_layout:[28,37],load_set:[28,37],load_widget:[8,37],local:[5,14,34],locale_nam:[17,37],lock:[10,37],lock_data:[33,37],log:[5,6,7,34],lst:[33,37],mac:38,main:[8,10,33,37],mainform:[5,6,14,34],mainwindow:[5,28,37],mainwindow_new:[14,18,34],manag:[5,6,34],mat:[33,37],matlab:36,max_siz:[33,37],max_stack_num:[33,37],member:[33,37],menu:[7,10,11,19,27,34],menu_tool_stat_bar:[14,15,34],messag:[8,27,37],metadata:[33,37],metadataset:[5,32,34],method:[10,12,13,33,37],model:[4,25,37],modification_callback:[33,37],modified_bi:[33,37],modify_data:[33,37],modul:[1,34],module_nam:[10,37],mousepressev:[26,37],mvc:[4,25,37],myentri:[12,37],myinterfac:[12,37],mymenu:[12,37],mysubwindow1:[12,37],mysubwindow2:[12,37],name:[7,8,21,27,28,37],ndarrai:[4,25,33,37],new_dock_window:[8,37],new_toolbar:[8,37],newitem:[5,14,34],no:[8,37],none:[3,4,5,7,8,19,21,23,25,26,27,28,29,33,37],normal:[1,2,34],not:[10,37],notfounderror:[33,37],notificationwidget:[14,15,34],np:[4,25,37],number:[8,37],numctrl:[3,37],numpi:[4,33,37],obj:[31,33,37],object:[7,8,9,10,12,13,14,17,18,25,28,31,33,34],of:[10,37],on_back_tab:[26,37],on_backspac:[26,37],on_boot_finish:[28,37],on_check:[3,37],on_choic:[3,37],on_close_request:[26,37],on_closed_act:[19,37],on_delet:[33,37],on_dock_widget_delet:[19,37],on_modif:[33,37],on_radio_button_toggl:[3,37],on_res:[23,37],on_return_press:[26,37],on_scrol:[3,26,37],on_spin:[3,37],on_tab:[26,37],on_text:[3,37],on_text_chang:[26,37],on_typ:[3,37],oncolor:[3,37],onli:[10,37],onselect:[3,37],ontext:[3,37],op:[8,37],openprocess:[5,14,34],option:[5,14,34],orient:[4,25,37],original_interfac:[10,37],ottom:[8,37],packag:[1,34],package_instal:[5,6,34],package_manag:[5,6,34],package_remov:[5,6,34],package_set:[5,6,34],package_upd:[5,6,34],paintev:[26,37],panda:[4,25,33,37],para_chang:[3,37],param:[7,21,23,28,37],param_chang:[3,37],parent:[3,4,7,19,21,23,25,26,27,28,29,37],path:[8,37],pathctrl:[3,37],pd:[4,25,37],platformutil:[5,14,34],plugininterfac:[7,37],pmappmodern:[1,34],pmcodeedittabwidget:[7,37],pmdockobject:[19,37],pmdockwidget:[14,18,34],pmeditorwithlinenumb:[26,37],pmext:[5,6,34],pmflowarea:[21,37],pmflowareawidget:[21,37],pmflowlayout:[23,37],pmflowlayoutwithgrid:[23,37],pmgcodeedit:[26,37],pmgdockwidget:[28,37],pmgtabletabwidget:[4,25,37],pmgtablewidget:[4,25,37],pmgwidget:[1,34],pmmainwindow:[14,18,34],pmprocess:[17,37],pmpushbutton:[14,18,34],pmpushbuttonpan:[19,37],pmscrollablelabel:[19,37],pmscrollarea:[14,18,34],pmtab:[14,18,34],pmtableview:[4,25,37],pmtabwidget:[21,37],pmtoolbar:[7,27,37],pmtoolbutton:[19,37],pmutil:[1,34],pmwidget:[5,14,34],pmworkspaceinspectwidget:[7,37],png:[24,37],pos:[8,37],posit:[8,29,37],prefac:34,present:[33,37],properti:[8,37],provid:[10,33,37],public_interfac:[7,37],publicinterfac:[8,37],push:[33,37],py2cn:35,py:[8,37],pycharm:38,pymin:[18,28,35,36],pyminer2:[1,34],pyqt5:[3,4,7,18,19,21,22,23,25,26,27,28,29,37,38],pyqt:[18,24,36,37],pyqt_tom_coffc:36,pyqtsource_rc:[1,5,34],python3:38,python:36,pythonhighlight:[26,37],qabstracttablemodel:[4,25,37],qaction:[27,37],qapplic:[5,37],qcleanupresourc:[14,37],qcloseev:[3,4,25,28,37],qdialog:[8,28,29,37],qdockwidget:[28,37],qgraphicsdropshadoweffect:[19,37],qgridlayout:[23,37],qicon:[7,19,27,37],qinitresourc:[14,37],qkeyev:[26,37],qlinenumberarea:[26,37],qmainwindow:[28,37],qmenu:[7,19,27,37],qmenu_demo:[14,18,34],qmodelindex:[4,25,37],qmouseev:[26,37],qpaintev:[26,37],qpoint:[29,37],qpushbutton:[7,19,27,37],qq:36,qresizeev:[21,26,37],qscrollarea:[21,37],qsize:[26,37],qss:[14,30,34],qss_tool:[14,30,34],qsstool:[31,37],qsyntaxhighlight:[26,37],qt:[4,25,36,37],qtableview:[4,25,37],qtablewidget:[4,25,37],qtabwidget:[4,21,25,37],qtcore:[4,25,29,37],qtextedit:[26,37],qtgui:[7,19,26,27,37],qtoolbar:[7,27,28,37],qtoolbutton:[7,19,37],qtwidget:[3,4,7,19,21,22,23,25,26,27,28,29,37],queue:[17,37],qwheelev:[26,37],qwidget:[3,7,8,19,21,22,23,26,27,28,29,37],raise_dock_into_view:[28,37],raise_into_view:[28,37],raise_widget_to_vis:[19,37],rang:[3,37],read:[10,33,37],read_and_writ:[10,37],read_data:[33,37],rect:[26,37],recyclebin:[5,32,34],redo:[33,37],refresh:[3,37],refresh_posit:[29,37],refresh_toolbar_appear:[28,37],refresh_view_config:[28,37],rehighlight:[26,37],reportwidget:[14,15,34],req:[33,37],reset:[8,37],resizeev:[21,26,37],resourc:[14,15,34],restor:[33,37],restore_data:[33,37],retranslateui:[9,28,37],right:[8,21,28,37],role:[4,25,37],row:[4,23,25,37],rowcount:[4,25,37],rowspan:[23,37],rule:[26,37],run:[10,12,13,37],run_command_in_termin:[17,37],run_extens:[10,37],save:[26,37],save_layout:[28,37],save_set:[28,37],sci:[4,25,37],select_typ:[33,37],self:[3,4,21,25,26,28,37],server:[10,33,37],set:[8,17,28,37],set_app:[3,37],set_btn_clicked_effect:[19,37],set_central_widget:[29,37],set_data:[4,25,37],set_data_2d:[4,25,37],set_layout_content_margin:[21,37],set_para:[3,37],set_posit:[29,37],set_qss_to_obj:[31,37],set_valu:[3,37],set_var:[33,37],set_var_dict:[33,37],set_width:[29,37],set_work_dir:[7,37],settingspanel:[3,37],setup_ui:[21,37],setupui:[9,28,37],shadow:[19,37],should:[10,37],show_dialog:[7,37],show_log:[7,37],show_tool_bar:[7,37],show_toolbar:[28,37],side:[7,8,28,37],signal:[7,37],signal_raise_into_view:[19,37],signal_sav:[26,37],size:[4,37],sizehint:[26,37],slider:[3,37],sourc:[5,14,24,34],sourcemgr:[14,18,34],spinbox:[3,37],sport:[3,37],standard:[28,37],start:[10,37],start_extens:[10,37],start_menu:[10,37],start_subwindow:[10,37],stepback:[33,37],stepforward:[33,37],str:[3,4,5,7,8,10,17,19,21,24,25,26,27,28,33,37],stream:[17,37],strformat:[4,25,37],submodul:[1,2,6,11,18,30,32,34],subpackag:[1,34],subwindow:[10,11,34],subwindow_class:[10,37],sumlink:36,switch_tool_bar:[7,37],switch_toolbar:[28,37],synchronis:[33,37],synchronise_data:[33,37],tab:[21,37],tab_button:[27,37],tab_id:[7,37],tabl:[1,2,14,18],tablemodel:[4,25,37],tablemodelforlist:[4,25,37],tablemodelfornumpyarrai:[4,25,37],tablemodelforpandasdatafram:[4,25,37],tableview:[1,2,14,18,34],tablewidget:[1,2,14,15,18,34],team:35,technolog:34,test:[10,12,13,37],test_comm:[5,14,34],test_demo:[5,6,34],test_extens:[10,11,34],test_extension2:[10,11,34],text:[3,7,8,17,19,21,27,28,37],textctrl:[3,14,18,34],texteditconsolewidget:[14,15,34],textwidgetlineshow:[14,18,34],that:[10,37],the:[10,37],then:[33,37],thi:[10,33,37],titl:[3,37],tk:[3,37],to:[10,37],to_decimal_str:[4,37],tool_widget_nam:[7,37],toolbar:[7,14,18,28,34],toolbar_nam:[7,37],toolbutton:[14,18,34],top:[28,37],toplevel:[5,14,34],toplevelwidget:[29,37],toptoolbar:[27,37],tp:[3,37],translat:[17,37],treeview:[14,15,34],tupl:[3,8,33,37],type:[3,17,37],type_nam:[33,37],ui:[1,5,8,34,36],ui_form:[9,28,37],ui_insert:[8,37],uiinsert:[5,6,34],uninstal:[8,37],unit:[3,37],unknown:[33,37],unlock:[10,37],unset_btn_clicked_effect:[19,37],up:[21,37],updat:[33,37],update_data_info:[33,37],updatelinenumberarea:[26,37],updatelinenumberareawidth:[26,37],updateui:[26,37],us:34,val:[4,25,37],valid:[3,37],valid_local:[17,37],valu:[3,10,37],value_input:[1,2,34],var_to_discard:[33,37],variabl:[5,10,32,34],variableerror:[33,37],varnam:[10,33,37],varset:[5,32,34],vartyp:[33,37],vec:[33,37],version:[8,37],view:[3,37],wait_kei:[17,37],wheelev:[26,37],widget:[7,14,15,19,21,23,27,28,29,34],widget_class:[7,8,37],widget_config:[8,37],widget_nam:[27,28,37],widgets_d:[3,37],widgettest:[8,37],width:[29,37],wiki:36,window:[14,18,34,38],work_dir:[7,37],workspac:[1,5,34],wouldblockerror:[33,37],wrap_interfac:[10,37],wrapper:[7,37],write:[10,33,37],write_data:[33,37],write_func:[10,37],www:35,x64:38,you:[3,37],yourentri:[13,37],yourinterfac:[13,37],yourmenu:[13,37],yoursubwindow1:[13,37],yoursubwindow2:[13,37],zh:[17,37]},titles:["app2 module","pyminer","pmgwidgets package","pmgwidgets.normal package","pmgwidgets.table package","pyminer2 package","pyminer2.extensions package","pyminer2.extensions.extensionlib package","pyminer2.extensions.extensions_manager package","pyminer2.extensions.package_manager package","pyminer2.extensions.test_demo package","pyminer2.extensions.test_demo.extensions package","pyminer2.extensions.test_demo.extensions.test_extension package","pyminer2.extensions.test_demo.extensions.test_extension2 package","pyminer2.ui package","pyminer2.ui.base package","pyminer2.ui.base.widgets package","pyminer2.ui.common package","pyminer2.ui.generalwidgets package","pyminer2.ui.generalwidgets.basicwidgets package","pyminer2.ui.generalwidgets.browser package","pyminer2.ui.generalwidgets.containers package","pyminer2.ui.generalwidgets.demos_and_tests package","pyminer2.ui.generalwidgets.layouts package","pyminer2.ui.generalwidgets.sourcemgr package","pyminer2.ui.generalwidgets.table package","pyminer2.ui.generalwidgets.textctrls package","pyminer2.ui.generalwidgets.toolbars package","pyminer2.ui.generalwidgets.window package","pyminer2.ui.pmwidgets package","pyminer2.ui.source package","pyminer2.ui.source.qss package","pyminer2.workspace package","pyminer2.workspace.datamanager package","Welcome to PyMiner\u2019s documentation!","Introduction","Join Us","API Reference","Technology"],titleterms:{aboutm:[15,37],and:34,api:[34,37],app2:[0,37],applicationtest:[28,37],base:[15,16,37],baseext:[7,37],basicwidget:[19,37],brief:35,browser:[20,37],cloud:38,cmd:38,com:38,common:[17,37],consolewidget:[16,37],contain:[21,37],content:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,37],contribut:36,controlpanel:[16,37],convert:[33,37],cut:35,datamanag:[33,37],dataset:[33,37],demos_and_test:[22,37],develop:[36,38],document:34,entri:[12,13,37],env_manag:[9,37],environ:38,except:[33,37],exe:38,extens:[6,7,8,9,10,11,12,13,37],extension_lib:[7,37],extensionlib:[7,10,37],extensionload:[8,37],extensions_manag:[8,37],flow:[15,37],flowarea:[21,37],flowlayout:[23,37],flowwidget:[16,37],generalwidget:[18,19,20,21,22,23,24,25,26,27,28,37],group:36,guid:34,highlight:[26,37],historyset:[33,37],how:36,http:38,ico:38,iconutil:[24,37],indic:34,instal:38,interfac:[12,13,37],introduct:35,join:36,label:[19,37],layout:[23,37],licens:35,local:[17,37],log:[8,37],logo:38,mainform:[10,15,37],mainwindow_new:[28,37],manag:[8,37],menu:[12,13,37],menu_tool_stat_bar:[16,37],metadataset:[33,37],mirror:38,modul:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,37],newitem:[15,37],normal:[3,37],notificationwidget:[16,37],object:[19,37],openprocess:[17,37],option:[15,37],packag:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,37],package_instal:[9,37],package_manag:[9,37],package_remov:[9,37],package_set:[9,37],package_upd:[9,37],pip:38,platformutil:[17,37],pmappmodern:[5,37],pmdockwidget:[28,37],pmext:[7,37],pmgwidget:[2,3,4,37],pmmainwindow:[28,37],pmpushbutton:[19,37],pmscrollarea:[21,37],pmtab:[21,37],pmutil:[5,37],pmwidget:[29,37],prefac:36,py:38,pyinstal:38,pymin:[1,34,37,38],pyminer2:[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,37],pyminerpymin:38,pypi:38,pyqtsource_rc:[14,37],python:38,pythonpython:38,qmenu_demo:[22,37],qss:[31,37],qss_tool:[31,37],recyclebin:[33,37],refer:[34,37],reportwidget:[16,37],requir:38,resourc:[16,37],simpl:38,sourc:[30,31,37],sourcemgr:[24,37],submodul:[3,4,5,7,8,9,10,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,33,37],subpackag:[2,5,6,10,11,14,15,18,30,32,37],subwindow:[12,13,37],tabl:[4,25,34,37],tableview:[4,25,37],tablewidget:[4,16,25,37],technolog:38,tencent:38,test_comm:[17,37],test_demo:[10,11,12,13,37],test_extens:[12,37],test_extension2:[13,37],textctrl:[26,37],texteditconsolewidget:[16,37],textwidgetlineshow:[26,37],to:[34,36],toolbar:[27,37],toolbutton:[19,37],toplevel:[29,37],treeview:[16,37],txt:38,ui:[14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,37],uiinsert:[8,37],us:36,user:34,value_input:[3,37],variabl:[33,37],varset:[33,37],welcom:34,widget:[16,37],window:[28,37],workspac:[32,33,37]}}) \ No newline at end of file diff --git a/docs/_build/html/user/intro.html b/docs/_build/html/user/intro.html deleted file mode 100644 index 19182ccc9c30b3779c402f394467dc1b3071925f..0000000000000000000000000000000000000000 --- a/docs/_build/html/user/intro.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - - - - - Introduction — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Introduction

-
-

Brief

-

PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。官方网站:www.py2cn.com

-
-
-

License

-

本项目遵循GPL许可证。此外,对个人用户来说,本项目支持自由修改源码和使用,但是不支持任何未经授权许可的商用或其他盈利性行为,也不支持任何未经授权申请著作权的行为。如有违反以上许可,本项目管理团队有权进行否决。 许可解释权归属 PyMiner Development Team。

-
-
-

Cut

-
-

预览1(主界面)

-../_images/show1.jpg -
-
-

预览2(表格显示)

-../_images/show2.jpg -
-
-

预览3(编辑器)

-../_images/show3.png -
-
-
- - -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/user/joinus.html b/docs/_build/html/user/joinus.html deleted file mode 100644 index 4760f9935b8b6c1fb97690ce9f3785e4e7a8a939..0000000000000000000000000000000000000000 --- a/docs/_build/html/user/joinus.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - Join Us — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Join Us

-
-

Preface

-

为了更便于推进项目,需要了解各位擅长的工作内容,请各位群友修改自己的备注为:方向+昵称,例如pyqt_tom_coffce

-
-
-

Develop Group

-

目前开发组已经有pyqt、算法、仿真、插件、网站、c++、项目管理多个小分队,有意向在任意领域进行参与贡献的小伙伴请直接加入小分队QQ群!

-

PyMiner开发者QQ总群:945391275

-

pyqt小分队:907932713

-

算法小分队:605160230

-

仿真小分队:915736652

-

插件小分队:689417488

-

C++小分队:205591506

-

网站小分队:1131420577

-

项目管理小分队:827058366

-

产品经理/需求分析师小分队:1026801187

-
-
-

How to Contribute::

-

要真正的参与项目,除了需要了解自身特长之外,还需要了解这个项目的基本情况。在Wiki的“ 项目说明 ”我们有对项目的背景做一些介绍,在“ 项目计划 ”中我们对当前我们正在做的事情以及下一步的项目计划做了概要性描述。

-

如果你是偏产品经理和需求分析师方面的,想要为项目做些贡献,我们希望你能对matlab多一些认识,毕竟我们的目标是进行matlab替代。在此基础上,希望你能帮助我们进行需求分解,将matlab的功能模块按照重要性、优先级进行细化分解,以便我们能够更专注于细节进行实现。

-

如果你是偏qt pyqt python 方向的,想要在PyMiner的界面UI或功能方面进行参与,我们也很希望你能真正的参与到项目的代码贡献当中。在这之前你可能还需要了解我们的代码结构(在wiki的“ 开发者指南 ”中我们会有相应介绍),编码规范(在wiki的“ 编程规范 ”中)。

-

如果你是仿真方向或对Sumlink有所研究,除了项目基础信息之外,你还需要了解项目的插件系统,目前在PyMiner中,更多功能将以插件的形式进行提供。而插件我们支持使用Python或c++等多种方式进行开发。

-

如果你是算法工程师,你将是这个项目的非常重要参与者,甚至可以说,我们的未来非常依赖你们的参与,而在PyMiner中,算法工程师的贡献,也将主要通过插件的形式进行完成,为此我们需要算法工程师和其他开发者齐心协力进行合作, 由算法进行后台计算并设计输入参数和输出形式,而pyqt开发者进行插件化改造实现 ,最终将算法以插件的形式对外提供。

-
-
- - -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/user/lib_ref.html b/docs/_build/html/user/lib_ref.html deleted file mode 100644 index 7fa20c8559048b6c4ccc6788f662f7ee4fbd6e50..0000000000000000000000000000000000000000 --- a/docs/_build/html/user/lib_ref.html +++ /dev/null @@ -1,3714 +0,0 @@ - - - - - - - - - - API Reference — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

API Reference

-
-
-

app2 module

-
-
-

pyminer

-
-
-
-
-

pmgwidgets.normal package

-
-

Submodules

-
-
-

pmgwidgets.normal.value_inputs module

-
-
-class pmgwidgets.normal.value_inputs.AnyType(parent, title, types=['Int', 'Float', 'Str'])
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_text(event)
-
- -
-
-on_type(event)
-
- -
-
-set_value(v)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.BaseParamWidget
-

基类:PyQt5.QtWidgets.QWidget

-

基础参数控件的类型。所有的参数控件都在其上派生而来。

-
-
-get_value()
-
- -
-
-is_key(event, type='')
-

‘dir’:判断方向键 -‘alpha’:判断是否为26个字母 -‘hex’:判断是否为十六进制数字或者字母 -‘digit’:判断是否为数字0~9 -‘valid’:包含数字、字母或者退格键。

-
- -
-
-para_changed()
-
- -
-
-set_app(app)
-
- -
-
-set_value()
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Check(title: str, initial_value: bool)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-

bool, ‘sport’, ‘do you like sport’,True

-
-
-get_value()
-
- -
-
-on_check()
-
- -
-
-set_value(value: bool)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Choice(choices, tp, title, unit)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-get_value()
-
- -
-
-on_choice(event=None)
-
- -
-
-on_radio_button_toggled()
-
- -
-
-set_value(x)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Choices(parent, choices, title)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_check()
-
- -
-
-set_value(value: list)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.ColorCtrl(title: str, initial_value: str)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-colorStr2Tup(value: str) → tuple
-
- -
-
-colorTup2Str(value: tuple) → str
-
- -
-
-get_value()
-
- -
-
-oncolor(event)
-
- -
-
-ontext(event)
-
- -
-
-set_value(color)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.FloatSlider(parent, rang, accury, title, unit='')
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value()
-
- -
-
-on_scroll(event)
-

只有这个方法会调用回调函数。原因:当用户通过拖动滚动条进行操作的时候,输入的值一定是合理的,无需进行判断; -当用户通过按spinbox或者是对spinbox输入文本的时候,只有文本符合规定的时候会对slider设置值,此时会调用这个方法。 -这样总能调用到这个回调函数。

-
- -
-
-on_spin()
-
- -
-
-on_text(event)
-
- -
-
-set_para(rang, accury)
-
- -
-
-set_value(n)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.Label(parent, title)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value(v)
-
- -
-
-set_value(v)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.NumCtrl(title: str, initial_value: int, unit: str, rang: tuple)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-

NumCtrl: derived from tk.Entry -用于输入数值。

-
-
-Bind(z, f)
-
- -
-
-Refresh()
-
- -
-
-f(e)
-
- -
-
-get_value()
-
- -
-
-ontext(event)
-
- -
-
-set_value(n)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.PathCtrl(parent, title, filt)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-get_value() → str
-
- -
-
-onselect(event)
-
- -
-
-ontext(event)
-
- -
-
-set_value(value: str)
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.SettingsPanel(values: Dict = None, views: List[Tuple[str]] = None, parent=None)
-

基类:PyQt5.QtWidgets.QWidget

-
-
-closeEvent(self, QCloseEvent)
-
- -
-
-get_value()
-
- -
-
-widgets_dic: Dict[str, PyQt5.QtWidgets.QWidget] = {}
-
- -
- -
-
-class pmgwidgets.normal.value_inputs.TextCtrl(title: str, initial_value: str)
-

基类:pmgwidgets.normal.value_inputs.BaseParamWidget

-
-
-Bind(z, f)
-
- -
-
-get_value() → str
-
- -
-
-ontext(event)
-
- -
-
-param_changed(event)
-
- -
-
-set_value(text: str)
-
- -
- -
-
-

Module contents

-
-
-
-

pmgwidgets package

-
-

Subpackages

-
-
-
-
-

Module contents

-
-
-
-

pmgwidgets.table package

-
-

Submodules

-
-
-

pmgwidgets.table.tableviews module

-

这是一个利用QT的MVC架构进行数据查看的表格。这个表格十分适合大量数据的查看,1000*1000规模的数据集可以做到秒开。 -其中定义了若干类。可以直接显示pd.DataFrame,np.array和list的TableView。

-
-
-class pmgwidgets.table.tableviews.PMTableView(data=None)
-

基类:PyQt5.QtWidgets.QTableView

-

基类,用于显示数据。输入数据类型为列表。

-
-
-set_data(data)
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForList(data: list)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为list的table model

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForNumpyArray(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pmgwidgets.table.tableviews.TableModelForPandasDataframe(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-headerData(self, int, Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-pmgwidgets.table.tableviews.dataformat(val, decimals=6, sci=False)
-

这只是暂时的strformat函数。如有可能,应当使用cython重写并且部署在动态链接库中,从而提升性能。 -Args:

-
-

val: -decimals: -sci:

-
-

Returns:

-
- -
-
-pmgwidgets.table.tableviews.to_decimal_str(cell_data: numpy.ndarray, decimals: int = 6)
-
- -
-
-

pmgwidgets.table.tablewidgets module

-
-
-class pmgwidgets.table.tablewidgets.PMGTableTabWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTabWidget

-
- -
-
-class pmgwidgets.table.tablewidgets.PMGTableWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTableWidget

-
-
-static check_data_can_be_displayed_by_table(data: Sized) → bool
-
- -
-
-closeEvent(self, QCloseEvent)
-
- -
-
-data_name: str = ''
-
- -
-
-data_shown
-
- -
-
-set_data_2d(data: np.ndarray, rows: int = None, columns: int = None)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions.extensionlib package

-
-

Submodules

-
-
-

pyminer2.extensions.extensionlib.baseext module

-
-
-class pyminer2.extensions.extensionlib.baseext.BaseExtension
-

基类:object

-
-
-extension_lib: extension_lib = None
-
- -
-
-get_widget(name: str)
-
- -
-
-public_interface: BaseInterface = None
-
- -
-
-widget_classes: Dict[str, QWidget] = None
-
- -
-
-widgets: Dict[str, QWidget] = None
-
- -
- -
-
-class pyminer2.extensions.extensionlib.baseext.BaseInterface
-

基类:object

-
-
-hello()
-
- -
- -
-
-

pyminer2.extensions.extensionlib.extension_lib module

-
-
-pyminer2.extensions.extensionlib.extension_lib.wrapper()
-
- -
-
-

pyminer2.extensions.extensionlib.pmext module

-
-
-class pyminer2.extensions.extensionlib.pmext.PluginInterface
-

基类:object

-
-
-class Signals
-

基类:object

-
-
-static get_main_window_close_signal()
-
- -
- -
-
-static add_docked_widget(dock_name: str, widget: PyQt5.QtWidgets.QWidget, text: str, side: str = 'left')
-
- -
-
-static add_tool_bar(name: str, toolbar: PyQt5.QtWidgets.QToolBar, text: str)
-
- -
-
-static append_to_context_menu(text: str, command: Callable, icon_path: str)
-

添加到鼠标右键菜单当中。 -Args:

-
-

text: -command: -icon_path:

-
-

Returns:

-
- -
-
-static append_to_sidebar(text: str, command: Callable, icon_path: str)
-

添加到右侧工具栏中。 -Args:

-
-

text:工具栏显示的文字。一般时候工具栏的文字是不会显示在界面上的,但鼠标悬停时会显示出来。 -command: 点击时调用的函数 -icon_path: 图标的文件路径,不得为空。

-
-

Returns:None

-
- -
-
-static append_to_toolbar(toolbar_name: str, text: str, icon: PyQt5.QtGui.QIcon, menu: PyQt5.QtWidgets.QMenu) → PyQt5.QtWidgets.QToolButton
-
-
Args:

text:工具栏显示的文字。一般时候工具栏的文字是不会显示在界面上的,但鼠标悬停时会显示出来。 -icon: 图标 -toolbar_name:工具栏的名称。

-
-
-

Returns:None

-
- -
-
-static append_to_toolbox(tab_id: int, icon_path: str, text: str, command: callable)
-

插入到工具箱中按钮。 -Args:

-
-

tab_id: -icon_path: -text: -command:

-
-

Returns:

-
- -
-
-static append_to_tray_menu(text: str, command: Callable)
-

添加到托盘菜单栏。 -Args:

-
-

text: 菜单的文字内容 -command: 点击菜单触发的函数

-
-

Returns:

-
- -
-
-static append_widget_to_toolbar(toolbar_name: str, widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-static get_console() → ConsoleWidget
-

获取控制台的实例。

-
- -
-
-static get_data_manager() → DataManager
-

# 获取数据管理类,返回DataManager

-
- -
-
-static get_dialog_class(dialog_name: str)
-

获取对话框类的方式。

-
- -
-
-static get_editor() → PMCodeEditTabWidget
-
- -
-
-static get_root_dir() → str
-

获取项目的根目录

-
- -
-
-static get_toolbar(toolbar_name: str) → PMToolBar
-

获取工具栏 -:param toolbar_name: -:return:

-
- -
-
-static get_toolbar_widget(toolbar_name: str, tool_widget_name: str) → PyQt5.QtWidgets.QPushButton
-
- -
-
-static get_work_dir() → str
-

获取当前工作路径

-
- -
-
-static get_workspace_inspector() → PMWorkspaceInspectWidget
-
- -
-
-static set_work_dir(work_dir: str) → None
-

设置当前工作路径

-
- -
-
-static show_dialog(dialog_name: str, parent=None, args=())
-

对话框类必须有parent作为输入参数。否则对话框将无法显示。 -另外还可以通过args选项指定除了parent之外的其他输入参数。

-
- -
-
-static show_log(level: str, module: str, content: str)
-

在日志窗口显示log。 -:param level: 类型,比如‘info’ -:param module: 模块。比如’Jupyter’ -:param content: 内容。自定义的字符串 -:return: -效果: -调用——PluginInterface.show_log(‘info’,’CodeEditor’,’新建文件’) -输出——2020-08-29 23:43:10 hzy INFO [CodeEditor]:新建文件

-
- -
-
-static show_tool_bar(toolbar_name: str)
-

切换工具栏 -:param toolbar_name: -:return:

-
- -
-
-static switch_tool_bar(toolbar_name: str)
-

切换工具栏 -:param toolbar_name: -:return:

-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions.extensions_manager package

-
-

Submodules

-
-
-

pyminer2.extensions.extensions_manager.ExtensionLoader module

-
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.ExtensionLoader
-

基类:object

-
-
-binding_info()
-
- -
-
-create_public_interface(interface)
-
- -
-
-import_module(path)
-
- -
-
-load(file, ui_inserters)
-
- -
-
-load_class(file, class_name)
-
- -
-
-load_widget(widget_config)
-
- -
-
-reset()
-
- -
- -
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.Info(icon, name, display_name, version, description, path)
-

基类:tuple

-
-
-property description
-

Alias for field number 4

-
- -
-
-property display_name
-

Alias for field number 2

-
- -
-
-property icon
-

Alias for field number 0

-
- -
-
-property name
-

Alias for field number 1

-
- -
-
-property path
-

Alias for field number 5

-
- -
-
-property version
-

Alias for field number 3

-
- -
- -
-
-class pyminer2.extensions.extensions_manager.ExtensionLoader.PublicInterface
-

基类:object

-
- -
-
-

pyminer2.extensions.extensions_manager.UIInserter module

-

控件插入器 -作者:冰中火,侯展意

-

这是加载UI控件的插件类。 -插件导入的时候,传递的widget_class是控件的类。 -1、对于新建的工具栏类、插入工具栏的控件类、插入主窗口的控件类,控件插入器直接将控件类实例化, -然后插入在由config.json中指定的位置; -2、对于对话框类,控件插入器不会将其实例化,而会将其保存在对话框类管理器中。使用时,调用相应的方法,可以显示对话框。 -请注意,对话框并不是什么只能问问题,点‘确定、取消’的类。只要继承QDialog的界面都要这样处理。 -以上1中所述的情况将在应用初始化时完成;而2则是动态的过程,可以在应用初始化完成后就弹出对话框进行显示。

-

插件导入时参数由json中的config设置项所决定。

-

config:是一个字典,但是现在传入的参数还远远不够。 -以这个文件的json配置为例,有以下要求: -“file”:声明了控件类的入口位置。一般就是在main.py之中。 -position:插件插入位置。有两种选项:‘new_dock_window’和‘new_toolbar’ -config:设置属性。 -config.message:插件的设置信息,可以为空。 -config.name:插件的名称 -config.side:插件插入窗口时的位置(当position=new_dock_window时有效),有left -ight opottom四个选项 -config.text:插件的文字。会显示在dockwidget或者工具栏上 -{

-
-

“file”:”main.py”, -“widget_class”:”WidgetTest”, -“position”:”new_dock_window”, -“config”:{

-
-

“message”:”no”, -“name”:”code_editor”, -“side”: “right”, -“text”: “编辑器”

-
-

}

-
-

}

-

插件管理器下一步的目的就是将插件尽可能不一次性的加载完,插件可以自行设置插入到程序的时间, -尽可能在主界面发出初始化完成信号之后在进行调用。

-
-
-class pyminer2.extensions.extensions_manager.UIInserter.UiInserter
-

基类:dict

-
-
-append_to_toolbar(widget_class: QWidget, config=None)
-
- -
-
-new_dock_window(widget_class: QWidget, config=None)
-
- -
-
-new_toolbar(widget_class: QWidget, config=None)
-
- -
- -
-
-pyminer2.extensions.extensions_manager.UIInserter.get_dock_by_position(pos: str)
-
- -
-
-pyminer2.extensions.extensions_manager.UIInserter.get_item_coor(coors: set, pos: str)
-
- -
-
-

pyminer2.extensions.extensions_manager.log module

-
-
-pyminer2.extensions.extensions_manager.log.assert_(boolean, text)
-

boolean:bool -text:str -若bool为false,以异常级输出text

-
- -
-
-pyminer2.extensions.extensions_manager.log.error(text)
-
- -
-
-pyminer2.extensions.extensions_manager.log.log(text)
-

日志输出text

-
- -
-
-

pyminer2.extensions.extensions_manager.manager module

-
-
-class pyminer2.extensions.extensions_manager.manager.ExtensionsManager
-

基类:object

-

扩展管理类

-
-
-get_ext_by_id(id_)
-

通过id获取扩展

-
- -
-
-get_ext_by_name(name)
-

通过名称获取扩展

-
- -
-
-install(path)
-

本地安装扩展

-
- -
-
-install_web(name, version='')
-
- -
-
-load()
-

加载扩展

-
- -
-
-load_one(name)
-
- -
-
-uninstall(id_)
-

卸载扩展

-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions.package_manager package

-
-

Submodules

-
-
-

pyminer2.extensions.package_manager.env_manager module

-
-
-class pyminer2.extensions.package_manager.env_manager.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_install module

-
-
-class pyminer2.extensions.package_manager.package_install.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_manager module

-
-
-

pyminer2.extensions.package_manager.package_remove module

-
-
-class pyminer2.extensions.package_manager.package_remove.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_setting module

-
-
-class pyminer2.extensions.package_manager.package_setting.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.extensions.package_manager.package_update module

-
-
-class pyminer2.extensions.package_manager.package_update.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions package

-
-

Subpackages

-
-
-
-
-

Module contents

-
-
-
-

pyminer2.extensions.test_demo.extensions package

-
-

Subpackages

-
-
-
-
-

Module contents

-
-
-
-

pyminer2.extensions.test_demo.extensions.test_extension2 package

-
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.entry module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.entry.YourEntry(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Entry

-
-
-run()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.interface module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.interface.YourInterface
-

基类:object

-
-
-method()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.menu module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.menu.YourMenu(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Menu

-
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension2.subwindow module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow1(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensions.test_extension2.subwindow.YourSubWindow2(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions.test_demo.extensions.test_extension package

-
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensions.test_extension.entry module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.entry.MyEntry(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Entry

-
-
-run()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.interface module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.interface.MyInterface
-

基类:object

-
-
-method()
-
- -
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.menu module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.menu.MyMenu(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.Menu

-
- -
-
-

pyminer2.extensions.test_demo.extensions.test_extension.subwindow module

-
-
-class pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow1(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensions.test_extension.subwindow.MySubWindow2(config: dict)
-

基类:pyminer2.extensions.test_demo.extensionlib.SubWindow

-
-
-test()
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.extensions.test_demo package

-
-

Subpackages

-
-
-
-
-

Submodules

-
-
-

pyminer2.extensions.test_demo.extensionlib module

-
-
-class pyminer2.extensions.test_demo.extensionlib.DataClient
-

基类:object

-

This class provides methods for data exchange -with the data server. Instances of this class -can be created in entry’s run function. The -variables should be a JSON object that contains -varnames and corresponding values.

-
-
-lock(varname: str)
-
- -
-
-read(varname: str) → object
-
- -
-
-read_and_write(varname: str, write_func)
-
- -
-
-unlock(varname: str)
-
- -
-
-write(variables: dict)
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.Entry(config: dict)
-

基类:object

-
-
-get_dependency_interface(extension_name: str) → object
-
- -
-
-get_interface() → object
-
- -
-
-run()
-
- -
-
-start_menu(config: dict)pyminer2.extensions.test_demo.extensionlib.Menu
-
- -
-
-start_subWindow(subWindow_class: str, config: dict)pyminer2.extensions.test_demo.extensionlib.SubWindow
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.Menu(config: dict)
-

基类:object

-

Do not create instance of this class, implement -it and call the function start_menu in entry -class to get its instance.

-
-
-test()
-
- -
- -
-
-class pyminer2.extensions.test_demo.extensionlib.SubWindow(config: dict)
-

基类:object

-

Do not create instance of this class, implement -it and call the function start_subwindow in -entry class to get its instance.

-
-
-test()
-
- -
- -
-
-

pyminer2.extensions.test_demo.mainform module

-
-
-class pyminer2.extensions.test_demo.mainform.Extension(info)
-

基类:object

-
-
-dynamic_binding()
-
- -
-
-end()
-
- -
-
-get_interface()
-
- -
-
-import_module(module_name)
-
- -
-
-life_period(run, extension)
-
- -
-
-start()
-
- -
-
-start_menu(config: dict)pyminer2.extensions.test_demo.extensionlib.Menu
-
- -
-
-start_subwindow(subwindow_class: str, config: dict)pyminer2.extensions.test_demo.extensionlib.SubWindow
-
- -
-
-wrap_interface(original_interface)
-
- -
- -
-
-class pyminer2.extensions.test_demo.mainform.MainForm
-

基类:object

-
-
-end_extension(extension: pyminer2.extensions.test_demo.mainform.Extension)
-
- -
-
-flush()
-

test only

-
- -
-
-get_dependency_interface(extension_name: str) → object
-
- -
-
-load_extension(extension_package: str)
-
- -
-
-run_extension(extension_name: str)
-
- -
-
-start_extension(extension: pyminer2.extensions.test_demo.mainform.Extension)
-
- -
-
-start_menu(start_menu)
-
- -
-
-start_subwindow(start_subwindow)
-
- -
- -
-
-pyminer2.extensions.test_demo.mainform.main()
-
- -
-
-

Module contents

-
-
-
-

pyminer2 package

-
-

Subpackages

-
-
-
-
-

Submodules

-
-
-

pyminer2.pmappmodern module

-
-
-

pyminer2.pmutil module

-
-
-pyminer2.pmutil.get_application() → None
-

获取QApplication -Returns:

-
- -
-
-pyminer2.pmutil.get_main_window() → pyminer2.pmappmodern.MainWindow
-

获取主窗口或者主控件。 -Returns:

-
- -
-
-pyminer2.pmutil.get_root_dir() → str
-

获取根路径。 -Returns:

-
- -
-
-pyminer2.pmutil.get_work_dir() → str
-

获取主窗口或者主控件。 -Returns:

-
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.base package

-
-

Subpackages

-
-
-
-
-

Submodules

-
-
-

pyminer2.ui.base.aboutMe module

-
-
-

pyminer2.ui.base.flow module

-
-
-

pyminer2.ui.base.mainForm module

-
-
-

pyminer2.ui.base.newItem module

-
-
-

pyminer2.ui.base.option module

-
-
-

Module contents

-
-
-
-

pyminer2.ui.base.widgets package

-
-

Submodules

-
-
-

pyminer2.ui.base.widgets.consolewidget module

-
-
-

pyminer2.ui.base.widgets.controlpanel module

-
-
-

pyminer2.ui.base.widgets.flowwidget module

-
-
-

pyminer2.ui.base.widgets.menu_tool_stat_bars module

-
-
-

pyminer2.ui.base.widgets.notificationwidget module

-
-
-

pyminer2.ui.base.widgets.reportwidget module

-
-
-

pyminer2.ui.base.widgets.resources module

-
-
-

pyminer2.ui.base.widgets.tablewidget module

-
-
-

pyminer2.ui.base.widgets.texteditconsolewidget module

-
-
-

pyminer2.ui.base.widgets.treeviews module

-
-
-

Module contents

-
-
-
-

pyminer2.ui.common package

-
-

Submodules

-
-
-

pyminer2.ui.common.locale module

-
-
-class pyminer2.ui.common.locale.Locale
-

基类:object

-
-
-add_locale(locale_name: str, translations: Dict[str, str])
-
- -
-
-locale: str = 'zh'
-
- -
-
-translate(text: str) → str
-
- -
-
-translations: Dict[str, Dict] = {}
-
- -
-
-valid_locales: set = {'en', 'zh'}
-
- -
- -
-
-

pyminer2.ui.common.openprocess module

-
-
-class pyminer2.ui.common.openprocess.PMProcess(args: List[str])
-

基类:object

-
-
-consoleLoop()
-
- -
-
-enqueue_stream(stream, queue, type)
-
- -
- -
-
-

pyminer2.ui.common.platformutil module

-
-
-pyminer2.ui.common.platformutil.check_platform() → str
-
- -
-
-pyminer2.ui.common.platformutil.run_command_in_terminal(cmd: str, close_mode: str = 'wait_key')
-
- -
-
-

pyminer2.ui.common.test_comm module

-
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.basicwidgets package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.basicwidgets.labels module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.labels.PMScrollableLabel(parent=None)
-

基类:PyQt5.QtWidgets.QWidget

-
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.object module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.object.PMDockObject
-

基类:object

-
-
-on_closed_action = 'hide'
-
- -
-
-on_dock_widget_deleted()
-
- -
-
-raise_widget_to_visible(widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-signal_raise_into_view
-
- -
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons.PMPushButtonPane
-

基类:PyQt5.QtWidgets.QWidget

-
-
-add_button(text: str = '', icon: PyQt5.QtGui.QIcon = None, menu: PyQt5.QtWidgets.QMenu = None, height: int = 30, font_size: int = 14) → PyQt5.QtWidgets.QPushButton
-
- -
-
-add_buttons(button_num: int = 2, text: list = None, icon_path: list = None, menu: list = None) → List[PyQt5.QtWidgets.QPushButton]
-
- -
- -
-
-

pyminer2.ui.generalwidgets.basicwidgets.toolbutton module

-
-
-class pyminer2.ui.generalwidgets.basicwidgets.toolbutton.PMToolButton(parent=None)
-

基类:PyQt5.QtWidgets.QToolButton

-
-
-set_btn_clicked_effect()
-
- -
-
-shadow = <PyQt5.QtWidgets.QGraphicsDropShadowEffect object>
-
- -
-
-unset_btn_clicked_effect()
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.browser package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.browser.browser module

-
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.containers package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.containers.PMTab module

-
-
-class pyminer2.ui.generalwidgets.containers.PMTab.PMTabWidget
-

基类:PyQt5.QtWidgets.QTabWidget

-
-
-addScrolledAreaTab(widget: PyQt5.QtWidgets.QWidget, a1: str) → int
-

添加使用QScrollArea包裹的Tab。 -:param widget: -:param a1: -:return:

-
- -
-
-setup_ui()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.containers.flowarea module

-

集成了流式布局、按钮排布的窗口。

-
-
-class pyminer2.ui.generalwidgets.containers.flowarea.PMFlowArea(parent=None)
-

基类:PyQt5.QtWidgets.QScrollArea

-
-
-add_tool_button(name: str, text: str, icon_path: str = '')
-
- -
-
-add_widget(w: PyQt5.QtWidgets.QWidget)
-
- -
-
-set_layout_content_margins(left: int, right: int, up: int, down: int)
-
- -
-
-setup_ui()
-
- -
- -
-
-class pyminer2.ui.generalwidgets.containers.flowarea.PMFlowAreaWidget
-

基类:PyQt5.QtWidgets.QWidget

-
-
-add_widget(w: PyQt5.QtWidgets.QWidget)
-
- -
-
-resizeEvent(self, QResizeEvent)
-
- -
-
-setup_ui()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.containers.pmscrollarea module

-
-
-class pyminer2.ui.generalwidgets.containers.pmscrollarea.PMScrollArea
-

基类:PyQt5.QtWidgets.QScrollArea

-
-
-setup_ui()
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.demos_and_tests package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo module

-
-
-class pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo.Demo
-

基类:PyQt5.QtWidgets.QWidget

-
-
-A()
-
- -
-
-B(action)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.layouts package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.layouts.flowlayout module

-
-
-class pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayout(parent=None, initial_columns=3, column_width=100)
-

基类:PyQt5.QtWidgets.QGridLayout

-
-
-add_widget(w: PyQt5.QtWidgets.QWidget) → None
-

添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 -:param w: -:param row: -:param column: -:param rowSpan: -:param columnSpan: -:return:

-
- -
-
-on_resize()
-

在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: -注意这个方法无法自动调用,只能依靠它的父控件。 -1 2 3 4 -5 6 7 8 -9 -:return:

-
- -
- -
-
-class pyminer2.ui.generalwidgets.layouts.flowlayout.PMFlowLayoutWithGrid(parent=None, column_width=100)
-

基类:PyQt5.QtWidgets.QGridLayout

-

流式布局,继承自QGridLayout,以Grid的方式添加widget。 -主要作用是在保证兼容代码的基础上,做到流式布局。

-
-
-addWidget(w: PyQt5.QtWidgets.QWidget, row: int, column: int, rowSpan: int, columnSpan: int) → None
-

添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 -:param w: -:param row: -:param column: -:param rowSpan: -:param columnSpan: -:return:

-
- -
-
-on_resize()
-

在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: -注意这个方法无法自动调用,只能依靠它的父控件。 -1 2 3 4 -5 6 7 8 -9 -:return:

-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets package

-
-

Subpackages

-
-
-
-
-

Module contents

-

generalwidgets是PyMiner继承于PyQt5的标准控件库。这个控件库封装PyQt中的标准控件,进行样式或者布局等等的设置,最终得到PyMiner需要的部件。

-
-
-
-

pyminer2.ui.generalwidgets.sourcemgr package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.sourcemgr.iconutils module

-
-
-pyminer2.ui.generalwidgets.sourcemgr.iconutils.create_icon(icon_path: str = ':/pyqt/source/images/New.png')
-
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.table package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.table.tableviews module

-

这是一个利用QT的MVC架构进行数据查看的表格。这个表格十分适合大量数据的查看,1000*1000规模的数据集可以做到秒开。 -其中定义了若干类。可以直接显示pd.DataFrame,np.array和list的TableView。

-
-
-class pyminer2.ui.generalwidgets.table.tableviews.PMTableView(data=None)
-

基类:PyQt5.QtWidgets.QTableView

-

基类,用于显示数据。输入数据类型为列表。

-
-
-set_data(data)
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForList(data: list)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为list的table model

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForNumpyArray(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-class pyminer2.ui.generalwidgets.table.tableviews.TableModelForPandasDataframe(data)
-

基类:PyQt5.QtCore.QAbstractTableModel

-

输入为pandas.DataFram的TableModel,用于在表格中显示数据。

-
-
-columnCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
-
-data(self, QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-headerData(self, int, Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole) → Any
-
- -
-
-rowCount(self, parent: QModelIndex = QModelIndex()) → int
-
- -
- -
-
-pyminer2.ui.generalwidgets.table.tableviews.dataformat(val, decimals=6, sci=False)
-

这只是暂时的strformat函数。如有可能,应当使用cython重写并且部署在动态链接库中,从而提升性能。 -Args:

-
-

val: -decimals: -sci:

-
-

Returns:

-
- -
-
-

pyminer2.ui.generalwidgets.table.tablewidgets module

-
-
-class pyminer2.ui.generalwidgets.table.tablewidgets.PMGTableTabWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTabWidget

-
- -
-
-class pyminer2.ui.generalwidgets.table.tablewidgets.PMGTableWidget(parent=None)
-

基类:PyQt5.QtWidgets.QTableWidget

-
-
-static check_data_can_be_displayed_by_table(data: object) → bool
-
- -
-
-closeEvent(self, QCloseEvent)
-
- -
-
-data_name: str = ''
-
- -
-
-data_shown
-
- -
-
-set_data_2d(data_name, data: np.ndarray, rows: int = None, columns: int = None)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.textctrls package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.textctrls.highlighter module

-
-
-class pyminer2.ui.generalwidgets.textctrls.highlighter.PythonHighlighter(parent=None)
-

基类:PyQt5.QtGui.QSyntaxHighlighter

-
-
-Formats = {}
-
- -
-
-Rules = []
-
- -
-
-highlightBlock(self, str)
-
- -
-
-static initializeFormats()
-
- -
-
-rehighlight(self)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.textctrls.textctrl module

-
-
-class pyminer2.ui.generalwidgets.textctrls.textctrl.PMGCodeEdit(parent=None)
-

基类:PyQt5.QtWidgets.QTextEdit

-
-
-autocomp_show(completions: list)
-
- -
-
-comment()
-
- -
-
-editIndent()
-
- -
-
-editUnindent()
-
- -
-
-hide_autocomp()
-
- -
-
-keyPressEvent(self, QKeyEvent)
-
- -
-
-on_back_tab()
-
- -
-
-on_backspace(key_backspace_event: PyQt5.QtGui.QKeyEvent)
-
- -
-
-on_close_request()
-
- -
-
-on_return_pressed()
-

按回车换行的方法 -:return:

-
- -
-
-on_tab()
-
- -
-
-on_text_changed()
-
- -
-
-save()
-
- -
-
-signal_save
-
- -
-
-updateUi()
-
- -
- -
-
-

pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module

-
-
-class pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.PMEditorWithLineNumber(parent=None)
-

基类:PyQt5.QtWidgets.QTextEdit

-
-
-highlightCurrentLine()
-
- -
-
-keyPressEvent(self, QKeyEvent)
-
- -
-
-lineNumberAreaPaintEvent(event)
-
- -
-
-lineNumberAreaWidth()
-
- -
-
-mousePressEvent(self, QMouseEvent)
-
- -
-
-on_scroll(event: PyQt5.QtGui.QWheelEvent = None)
-
- -
-
-resizeEvent(self, QResizeEvent)
-
- -
-
-updateLineNumberArea(rect, dy)
-
- -
-
-updateLineNumberAreaWidth(e)
-
- -
-
-wheelEvent(self, QWheelEvent)
-
- -
- -
-
-class pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow.QLineNumberArea(editor)
-

基类:PyQt5.QtWidgets.QWidget

-
-
-paintEvent(self, QPaintEvent)
-
- -
-
-sizeHint(self) → QSize
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.toolbars package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.toolbars.toolbar module

-
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.ActionWithMessage(text: str = '', icon: PyQt5.QtGui.QIcon = None, parent: PyQt5.QtWidgets.QWidget = None, message: str = '')
-

基类:PyQt5.QtWidgets.QAction

-
- -
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.PMToolBar
-

基类:PyQt5.QtWidgets.QToolBar

-
-
-add_buttons(button_num: int, names: List[str], texts: List[str], icons_path: List[str] = None) → List[PyQt5.QtWidgets.QPushButton]
-
- -
-
-add_menu_to(button_name: str, action_texts: List[str], action_commands: List[Callable]) → List[PyQt5.QtWidgets.QAction]
-
- -
-
-add_tool_button(name: str, text: str = '', icon: PyQt5.QtGui.QIcon = None, menu: PyQt5.QtWidgets.QMenu = None)
-
- -
-
-add_widget(name: str, widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-get_control_widget(widget_name: str) → PyQt5.QtWidgets.QPushButton
-
- -
-
-tab_button: PyQt5.QtWidgets.QPushButton = None
-
- -
- -
-
-class pyminer2.ui.generalwidgets.toolbars.toolbar.TopToolBar
-

基类:PyQt5.QtWidgets.QToolBar

-
-
-add_button(text: str)
-
- -
-
-get_button(name: str)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.generalwidgets.window package

-
-

Submodules

-
-
-

pyminer2.ui.generalwidgets.window.applicationtest module

-
-
-class pyminer2.ui.generalwidgets.window.applicationtest.MainWindow(parent=None)
-

基类:PyQt5.QtWidgets.QMainWindow, pyminer2.ui.generalwidgets.window.applicationtest.Ui_Form

-
- -
-
-class pyminer2.ui.generalwidgets.window.applicationtest.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.window.mainwindow_new module

-
-
-class pyminer2.ui.generalwidgets.window.mainwindow_new.MainWindow(parent=None)
-

基类:PyQt5.QtWidgets.QMainWindow, pyminer2.ui.generalwidgets.window.mainwindow_new.Ui_Form

-
- -
-
-class pyminer2.ui.generalwidgets.window.mainwindow_new.Ui_Form
-

基类:object

-
-
-retranslateUi(Form)
-
- -
-
-setupUi(Form)
-
- -
- -
-
-

pyminer2.ui.generalwidgets.window.pmdockwidget module

-
-
-class pyminer2.ui.generalwidgets.window.pmdockwidget.PMDockWidget(name, text='', parent: PyQt5.QtWidgets.QMainWindow = None)
-

基类:pyminer2.ui.generalwidgets.window.pmdockwidget.PMGDockWidget

-
-
-closeEvent(self, QCloseEvent)
-
- -
-
-raise_into_view()
-

将控件提升到能直接看到的位置。特别适用于两个选项卡叠在一起的情况。 -:return:

-
- -
- -
-
-class pyminer2.ui.generalwidgets.window.pmdockwidget.PMGDockWidget(name, text='', parent: PyQt5.QtWidgets.QMainWindow = None)
-

基类:PyQt5.QtWidgets.QDockWidget

-
- -
-
-

pyminer2.ui.generalwidgets.window.pmmainwindow module

-

这里定义了MainWindow的基类。 -基类主要包含带选项卡工具栏的管理功能,以及浮动窗口的管理功能 -添加浮动窗口时,默认‘关闭’事件就是隐藏。如果是彻底的关闭,需要进行重写。 -每次界面关闭时,布局会被存入文件pyminer/config/customized/layout.ini之中。再次启动时,若这个文件存在,就会加载,反之不会加载。

-
-
-class pyminer2.ui.generalwidgets.window.pmmainwindow.BaseMainWindow
-

基类:PyQt5.QtWidgets.QMainWindow

-
-
-add_widget_on_dock(dock_name: str, widget: PyQt5.QtWidgets.QWidget, text: str = '', side='left')
-
- -
-
-bind_events()
-

在启动的最后调用这个绑定事件的方法,让全部的控件都绑定事件。这样可以避免绑定的时候,由于对应控件未加载,发生找不到对应控件的错误 -:return:

-
- -
-
-delete_dock_widget(widget_name: str)
-

删除dock_widget。 -:param widget_name: -:return:

-
- -
-
-dialog_classes: Dict[str, QDialog] = {}
-
- -
-
-dock_places = {'bottom': 8, 'left': 1, 'right': 2, 'top': 4}
-
- -
-
-dock_widgets: Dict[str, PMDockWidget] = {}
-
- -
-
-get_dock_widget(widget_name: str) → PMDockWidget
-
- -
-
-init_toolbar_tab()
-
- -
-
-load_layout()
-
- -
-
-load_predefined_layout(layout_type: str = 'standard')
-
- -
-
-load_settings()
-
- -
-
-on_boot_finished()
-
- -
-
-raise_dock_into_view(dock_name: str)
-
- -
-
-refresh_toolbar_appearance()
-
- -
-
-refresh_view_configs()
-
- -
-
-save_layout()
-
- -
-
-save_settings()
-
- -
-
-settings = {}
-
- -
-
-show_toolbar(name)
-
- -
-
-switch_toolbar(name: str)
-
- -
-
-toolbars: Dict[str, PyQt5.QtWidgets.QToolBar] = {}
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.pmwidgets package

-
-

Submodules

-
-
-

pyminer2.ui.pmwidgets.toplevel module

-
-
-class pyminer2.ui.pmwidgets.toplevel.TopLevelWidget(parent=None)
-

基类:PyQt5.QtWidgets.QDialog

-
-
-refresh_position() → None
-
- -
-
-set_central_widget(widget: PyQt5.QtWidgets.QWidget)
-
- -
-
-set_position(position: PyQt5.QtCore.QPoint)
-
- -
-
-set_width(width: int)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui package

-
-

Subpackages

-
-
-
-
-

Submodules

-
-
-

pyminer2.ui.pyqtsource_rc module

-
-
-pyminer2.ui.pyqtsource_rc.qCleanupResources()
-
- -
-
-pyminer2.ui.pyqtsource_rc.qInitResources()
-
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.source.qss package

-
-

Submodules

-
-
-

pyminer2.ui.source.qss.qss_tools module

-
-
-class pyminer2.ui.source.qss.qss_tools.QssTools
-

基类:object

-

定义一个读取样式的工具类

-
-
-classmethod set_qss_to_obj(file_path, obj)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.ui.source package

-
-

Subpackages

-
-
-
-
-

Module contents

-
-
-
-

pyminer2.workspace.datamanager package

-
-

Submodules

-
-
-

pyminer2.workspace.datamanager.converter module

-
-
-class pyminer2.workspace.datamanager.converter.Converter(data_manager)
-

基类:object

-
-
-convert_dataframe(dataframe: pandas.core.frame.DataFrame) → dict
-
- -
-
-convert_list(lst: list) → dict
-
- -
-
-convert_ndarray(arr: numpy.ndarray) → dict
-
- -
-
-convert_to_data(var) → dict
-
- -
-
-convert_to_var(data: dict)
-
- -
-
-iconvert_dataframe(dataframe: pyminer2.workspace.datamanager.variable.Variable) → pandas.core.frame.DataFrame
-
- -
-
-iconvert_matrix(mat: pyminer2.workspace.datamanager.variable.Variable) → numpy.ndarray
-
- -
-
-iconvert_vector(vec: pyminer2.workspace.datamanager.variable.Variable) → numpy.ndarray
-
- -
- -
-
-exception pyminer2.workspace.datamanager.converter.ConverterError
-

基类:Exception

-
- -
-
-pyminer2.workspace.datamanager.converter.main()
-
- -
-
-

pyminer2.workspace.datamanager.datamanager module

-
-
-class pyminer2.workspace.datamanager.datamanager.DataManager
-

基类:object

-
-
-add_callbacks()
-
- -
-
-cancel(varname)
-
- -
-
-delete_data(varname: str)
-
- -
-
-get_all_var() → dict
-
- -
-
-get_data_info(varname: str) → dict
-
- -
-
-get_recyclebin() → list
-
- -
-
-get_var(varname: str)
-
- -
-
-lock_data(varname: str)
-
- -
-
-on_deletion(deletion_callback)
-
- -
-
-on_modification(modification_callback)
-
- -
-
-read_data(varname: str) → dict
-
- -
-
-redo(varname)
-
- -
-
-restore(index: int)
-
- -
-
-set_var(varname: str, variable, provider='unknown', **info)
-
- -
-
-set_var_dict(variables: dict, provider='unknown', info_dict: dict = {})
-
- -
-
-update_data_info(varname: str, **info)
-
- -
-
-write_data(varname: str, data: dict, provider='server')
-
- -
- -
-
-pyminer2.workspace.datamanager.datamanager.main()
-
- -
-
-

pyminer2.workspace.datamanager.dataset module

-
-
-class pyminer2.workspace.datamanager.dataset.DataSet
-

基类:dict

-
-
-compare(obj, req)
-
- -
-
-is_valid(obj: dict) → bool
-
- -
-
-read(key: str) → dict
-
- -
-
-select_type(type_name: str)
-
- -
-
-synchronise(key: str, obj: dict)
-
- -
-
-write(key: str, obj: dict)
-
- -
- -
-
-pyminer2.workspace.datamanager.dataset.main()
-
- -
-
-

pyminer2.workspace.datamanager.exceptions module

-
-
-exception pyminer2.workspace.datamanager.exceptions.ConflictError
-

基类:Exception

-
- -
-
-exception pyminer2.workspace.datamanager.exceptions.NotFoundError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.historyset module

-
-
-class pyminer2.workspace.datamanager.historyset.DataHistory(max_stack_num)
-

基类:list

-
-
-push(var)
-
- -
-
-stepback(var)
-
- -
-
-stepforward()
-
- -
- -
-
-exception pyminer2.workspace.datamanager.historyset.HistoryError
-

基类:Exception

-
- -
-
-class pyminer2.workspace.datamanager.historyset.HistorySet(max_stack_num=15)
-

基类:dict

-
-
-push(key: str, var)
-
- -
-
-stepback(key: str, var)
-
- -
-
-stepforward(key: str)
-
- -
- -
-
-

pyminer2.workspace.datamanager.metadataset module

-
-
-class pyminer2.workspace.datamanager.metadataset.MetaData(provider, **info)
-

基类:dict

-
- -
-
-class pyminer2.workspace.datamanager.metadataset.MetaDataSet
-

基类:dict

-
-
-define_data(key: str, info: pyminer2.workspace.datamanager.metadataset.MetaData)
-
- -
-
-delete_data(key: str)
-
- -
-
-lock_data(key: str)
-
- -
-
-modify_data(key: str, modified_by: str)
-
- -
-
-restore_data(key: str)
-
- -
-
-synchronise_data(key: str)
-
- -
-
-update([E, ]**F) → None. Update D from dict/iterable E and F.
-

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] -If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v -In either case, this is followed by: for k in F: D[k] = F[k]

-
- -
- -
-
-exception pyminer2.workspace.datamanager.metadataset.WouldBlockError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.recyclebin module

-
-
-class pyminer2.workspace.datamanager.recyclebin.RecycleBin(max_size=1000)
-

基类:list

-
-
-discard(varname: str, variable)
-
- -
-
-get_varname(index: int)
-
- -
-
-restore(index: int, var_to_discard=None) → tuple
-
- -
- -
-
-

pyminer2.workspace.datamanager.variable module

-
-
-class pyminer2.workspace.datamanager.variable.Variable(vartype: str, members: dict)
-

基类:dict

-
-
-dump()
-
- -
-
-dumps()
-
- -
-
-load(dct: dict)
-
- -
-
-loads(jsonstr: str)
-
- -
- -
-
-exception pyminer2.workspace.datamanager.variable.VariableError
-

基类:Exception

-
- -
-
-

pyminer2.workspace.datamanager.varset module

-
-
-class pyminer2.workspace.datamanager.varset.VarSet
-

基类:dict

-
-
-get_var(varname: str)
-
- -
-
-insert_builtin_types(builtin_types: dict)
-
- -
-
-set_var(varname: str, variable)
-
- -
- -
-
-

Module contents

-
-
-
-

pyminer2.workspace package

-
-

Subpackages

-
-
-
-
-

Module contents

-
-
- - -
- -
-
- - - - -
- -
-

- - © 版权所有 2020, PyMiner Development Team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/_build/html/user/tech.html b/docs/_build/html/user/tech.html deleted file mode 100644 index 66187322dcf18a061d3d6899771faf675846f803..0000000000000000000000000000000000000000 --- a/docs/_build/html/user/tech.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - - - Technology — PyMiner 0.0.1 文档 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Technology

-
-

Develop Environment

-

PyMiner项目开发环境基于Windows 10 X64,使用Python3.8+PyQt5.15+Pycharm进行技术开发, 同时,此项目支持跨平台,这意味着即使是Linux、Mac也可以直接使用或开发此软件!

-
-
-

Installation

-
-

下载项目源码

-
-
-

安装python并打开命令行工具,使用 pip install -r requirements.txt 导入python包,如果你的python依赖包下载太慢,我建议使用:pip install -i https://mirrors.cloud.tencent.com/pypi/simple -r requirements.txt

-
-
-

调用python 执行目录下pyminer.py,例如python安装在C盘根目录下,可以在cmd命令行中执行:C:pythonpython.exe C:PyMinerpyminer.py

-
-
-

此外,你也可以使用pyinstaller进行编译后使用,编译语句:pyinstaller -i logo.ico -w pyminer.py

-
-
-
- - -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index ed1b4ce2714092045673b2dce5736d3ad29ee6ff..0000000000000000000000000000000000000000 --- a/docs/conf.py +++ /dev/null @@ -1,157 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys - -sys.path.insert(0, os.path.abspath('..')) -sys.path.insert(0, os.path.abspath('..') + '/pyminer2') -sys.path.insert(0, os.path.abspath('..') + '/pmgwidgets') -sys.path.insert(0, os.path.abspath('..') + '/readme_figures') -sys.path.insert(0, os.path.abspath('..') + '/pmgwidgets') - -# -- Project information ----------------------------------------------------- - -project = 'PyMiner' -copyright = '2020, PyMiner Development Team' -author = 'PyMiner Development Team' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.0.1' -# The full version, including alpha/beta/rc tags. -release = '0.0.1' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - - -# The master toctree document. -master_doc = 'index' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -html_theme_options = {} - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = 'zh_CN' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - ] -} - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PyMinerdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'PyMiner.tex', 'PyMiner Documentation', - 'PyMiner Development Team', 'manual'), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'PyMiner', 'PyMiner Documentation', - [author], 1) -] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'PyMiner', 'PyMiner Documentation', - author, 'PyMiner', 'One line description of project.', - 'Miscellaneous'), -] diff --git a/docs/dts/app2.rst b/docs/dts/app2.rst deleted file mode 100644 index 4ff5d31efab5c6488bbefd3a0c308ddbc18b3efd..0000000000000000000000000000000000000000 --- a/docs/dts/app2.rst +++ /dev/null @@ -1,7 +0,0 @@ -app2 module -=========== - -.. automodule:: app2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/modules.rst b/docs/dts/modules.rst deleted file mode 100644 index 2db55fe5e3937c3d0f901ccf3deed5073eb8782c..0000000000000000000000000000000000000000 --- a/docs/dts/modules.rst +++ /dev/null @@ -1,9 +0,0 @@ -pyminer -======= - -.. toctree:: - :maxdepth: 4 - - app2 - pmgwidgets - pyminer2 diff --git a/docs/dts/pmgwidgets.normal.rst b/docs/dts/pmgwidgets.normal.rst deleted file mode 100644 index 41582119c96ebdb413613431855b65ea0dc0eaff..0000000000000000000000000000000000000000 --- a/docs/dts/pmgwidgets.normal.rst +++ /dev/null @@ -1,21 +0,0 @@ -pmgwidgets.normal package -========================= - -Submodules ----------- - -pmgwidgets.normal.value\_inputs module --------------------------------------- - -.. automodule:: pmgwidgets.normal.value_inputs - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.normal - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pmgwidgets.rst b/docs/dts/pmgwidgets.rst deleted file mode 100644 index 2b71277a4e546f65ad0a212f4cc8c180bd4fa1cb..0000000000000000000000000000000000000000 --- a/docs/dts/pmgwidgets.rst +++ /dev/null @@ -1,19 +0,0 @@ -pmgwidgets package -================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pmgwidgets.normal - pmgwidgets.table - -Module contents ---------------- - -.. automodule:: pmgwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pmgwidgets.table.rst b/docs/dts/pmgwidgets.table.rst deleted file mode 100644 index 82988eff55f237eed64ba821a326be42ec3dc52c..0000000000000000000000000000000000000000 --- a/docs/dts/pmgwidgets.table.rst +++ /dev/null @@ -1,29 +0,0 @@ -pmgwidgets.table package -======================== - -Submodules ----------- - -pmgwidgets.table.tableviews module ----------------------------------- - -.. automodule:: pmgwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pmgwidgets.table.tablewidgets module ------------------------------------- - -.. automodule:: pmgwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.table - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.extensionlib.rst b/docs/dts/pyminer2.extensions.extensionlib.rst deleted file mode 100644 index bebe3e024d6add3160781ef4b234da8b905799ef..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.extensionlib.rst +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.extensions.extensionlib package -======================================== - -Submodules ----------- - -pyminer2.extensions.extensionlib.baseext module ------------------------------------------------ - -.. automodule:: pyminer2.extensions.extensionlib.baseext - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.extension\_lib module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.extension_lib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.pmext module ---------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.pmext - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensionlib - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.extensions_manager.rst b/docs/dts/pyminer2.extensions.extensions_manager.rst deleted file mode 100644 index 53f92b4ac15fdcaddbf9feccd2b30be2ac6ef0cf..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.extensions_manager.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.extensions\_manager package -=============================================== - -Submodules ----------- - -pyminer2.extensions.extensions\_manager.ExtensionLoader module --------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.ExtensionLoader - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.UIInserter module ---------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.UIInserter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.log module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.log - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.manager module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.manager - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensions_manager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.package_manager.rst b/docs/dts/pyminer2.extensions.package_manager.rst deleted file mode 100644 index ecc8b09965408155b62a2091f350b03e69fab706..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.package_manager.rst +++ /dev/null @@ -1,61 +0,0 @@ -pyminer2.extensions.package\_manager package -============================================ - -Submodules ----------- - -pyminer2.extensions.package\_manager.env\_manager module --------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.env_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_install module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_install - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_manager module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_remove module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_remove - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_setting module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_setting - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_update module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_update - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.package_manager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.rst b/docs/dts/pyminer2.extensions.rst deleted file mode 100644 index 2eb1dc016f9cf75cca6f68daaa33f14614bd62e4..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.extensions package -=========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.extensionlib - pyminer2.extensions.extensions_manager - pyminer2.extensions.package_manager - pyminer2.extensions.test_demo - -Module contents ---------------- - -.. automodule:: pyminer2.extensions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.test_demo.extensions.rst b/docs/dts/pyminer2.extensions.test_demo.extensions.rst deleted file mode 100644 index b3eb3e7d27299762835f8bc2ce14331f5a72f0f4..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.test_demo.extensions.rst +++ /dev/null @@ -1,19 +0,0 @@ -pyminer2.extensions.test\_demo.extensions package -================================================= - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions.test_extension - pyminer2.extensions.test_demo.extensions.test_extension2 - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst b/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst deleted file mode 100644 index 1b636f70e730679b8893ec704eb7ccd33a911fff..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.test\_demo.extensions.test\_extension package -================================================================= - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension.entry module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.interface module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.menu module ---------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.subwindow module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst b/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst deleted file mode 100644 index 3a25526b0ad3c5fdedb4d605fa4503c9f168e5d7..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.test_demo.extensions.test_extension2.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.extensions.test\_demo.extensions.test\_extension2 package -================================================================== - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension2.entry module ------------------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.interface module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.menu module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.subwindow module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.extensions.test_demo.rst b/docs/dts/pyminer2.extensions.test_demo.rst deleted file mode 100644 index 6fe415622f2f8529feb54c491058b55629611db0..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.extensions.test_demo.rst +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.extensions.test\_demo package -====================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensionlib module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensionlib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.mainform module ----------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.mainform - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.rst b/docs/dts/pyminer2.rst deleted file mode 100644 index 5cbe121ddafd9725c5acb97b20e8ec64d2df4570..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.rst +++ /dev/null @@ -1,39 +0,0 @@ -pyminer2 package -================ - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions - pyminer2.ui - pyminer2.workspace - -Submodules ----------- - -pyminer2.pmappmodern module ---------------------------- - -.. automodule:: pyminer2.pmappmodern - :members: - :undoc-members: - :show-inheritance: - -pyminer2.pmutil module ----------------------- - -.. automodule:: pyminer2.pmutil - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2 - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.base.rst b/docs/dts/pyminer2.ui.base.rst deleted file mode 100644 index fad413b3fce875c16742dd2e7abb5a8f0eece312..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.base.rst +++ /dev/null @@ -1,61 +0,0 @@ -pyminer2.ui.base package -======================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base.widgets - -Submodules ----------- - -pyminer2.ui.base.aboutMe module -------------------------------- - -.. automodule:: pyminer2.ui.base.aboutMe - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.flow module ----------------------------- - -.. automodule:: pyminer2.ui.base.flow - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.mainForm module --------------------------------- - -.. automodule:: pyminer2.ui.base.mainForm - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.newItem module -------------------------------- - -.. automodule:: pyminer2.ui.base.newItem - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.option module ------------------------------- - -.. automodule:: pyminer2.ui.base.option - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.base.widgets.rst b/docs/dts/pyminer2.ui.base.widgets.rst deleted file mode 100644 index 16fb4b91ab324667562ec040a474b6818615803e..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.base.widgets.rst +++ /dev/null @@ -1,93 +0,0 @@ -pyminer2.ui.base.widgets package -================================ - -Submodules ----------- - -pyminer2.ui.base.widgets.consolewidget module ---------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.consolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.controlpanel module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.controlpanel - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.flowwidget module ------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.flowwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.menu\_tool\_stat\_bars module ------------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.menu_tool_stat_bars - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.notificationwidget module --------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.notificationwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.reportwidget module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.reportwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.resources module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.resources - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.tablewidget module -------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.tablewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.texteditconsolewidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.texteditconsolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.treeviews module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.treeviews - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base.widgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.common.rst b/docs/dts/pyminer2.ui.common.rst deleted file mode 100644 index 28bbff7e257e686372f9c1db8c9afb8522405e37..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.common.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.common package -========================== - -Submodules ----------- - -pyminer2.ui.common.locale module --------------------------------- - -.. automodule:: pyminer2.ui.common.locale - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.openprocess module -------------------------------------- - -.. automodule:: pyminer2.ui.common.openprocess - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.platformutil module --------------------------------------- - -.. automodule:: pyminer2.ui.common.platformutil - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.test\_comm module ------------------------------------- - -.. automodule:: pyminer2.ui.common.test_comm - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.common - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.basicwidgets.rst b/docs/dts/pyminer2.ui.generalwidgets.basicwidgets.rst deleted file mode 100644 index 6a74ea0302a17efd13d506a0fd1353ff1c6689fc..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.basicwidgets.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.generalwidgets.basicwidgets package -=============================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.basicwidgets.labels module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.labels - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.object module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.object - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module ------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.toolbutton module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.toolbutton - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.browser.rst b/docs/dts/pyminer2.ui.generalwidgets.browser.rst deleted file mode 100644 index 49ae6ffc55ab51c6907926506495c2cff66d7d72..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.browser.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.browser package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.browser.browser module -------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser.browser - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.containers.rst b/docs/dts/pyminer2.ui.generalwidgets.containers.rst deleted file mode 100644 index 98d7c387869969e634b340bea0b690ce87792132..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.containers.rst +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.ui.generalwidgets.containers package -============================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.containers.PMTab module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.PMTab - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.flowarea module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.containers.flowarea - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.pmscrollarea module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.pmscrollarea - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst b/docs/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst deleted file mode 100644 index 019f849ed6a83f3f23bc7c0ab747542fa2a92f02..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.demos_and_tests.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.demos\_and\_tests package -==================================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.demos\_and\_tests.qmenu\_demo module ---------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.layouts.rst b/docs/dts/pyminer2.ui.generalwidgets.layouts.rst deleted file mode 100644 index eb1919f243b8583e79f8ffa4c3ee94de91a8f1a2..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.layouts.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.layouts package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.layouts.flowlayout module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts.flowlayout - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.rst b/docs/dts/pyminer2.ui.generalwidgets.rst deleted file mode 100644 index 0e8db3e1ec940a19d7300049a46d96ffe0a35185..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.rst +++ /dev/null @@ -1,27 +0,0 @@ -pyminer2.ui.generalwidgets package -================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.generalwidgets.basicwidgets - pyminer2.ui.generalwidgets.browser - pyminer2.ui.generalwidgets.containers - pyminer2.ui.generalwidgets.demos_and_tests - pyminer2.ui.generalwidgets.layouts - pyminer2.ui.generalwidgets.sourcemgr - pyminer2.ui.generalwidgets.table - pyminer2.ui.generalwidgets.textctrls - pyminer2.ui.generalwidgets.toolbars - pyminer2.ui.generalwidgets.window - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.sourcemgr.rst b/docs/dts/pyminer2.ui.generalwidgets.sourcemgr.rst deleted file mode 100644 index f2abea94f3bb41a0346a7af9eb084953256403d7..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.sourcemgr.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.sourcemgr package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.sourcemgr.iconutils module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr.iconutils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.table.rst b/docs/dts/pyminer2.ui.generalwidgets.table.rst deleted file mode 100644 index 8e191e84acef2ce0ed1f4ab17a0c2eb902107af4..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.table.rst +++ /dev/null @@ -1,29 +0,0 @@ -pyminer2.ui.generalwidgets.table package -======================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.table.tableviews module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.table.tablewidgets module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.table - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.textctrls.rst b/docs/dts/pyminer2.ui.generalwidgets.textctrls.rst deleted file mode 100644 index 73ba688af6bae47d237cc1d071eff2b888cc55df..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.textctrls.rst +++ /dev/null @@ -1,37 +0,0 @@ -pyminer2.ui.generalwidgets.textctrls package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.textctrls.highlighter module -------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.highlighter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textctrl module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textctrl - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module --------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.toolbars.rst b/docs/dts/pyminer2.ui.generalwidgets.toolbars.rst deleted file mode 100644 index d1b0a959c9915f94c66301f23311f4d374354dbd..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.toolbars.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.generalwidgets.toolbars package -=========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.toolbars.toolbar module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars.toolbar - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.generalwidgets.window.rst b/docs/dts/pyminer2.ui.generalwidgets.window.rst deleted file mode 100644 index c143a91890bb221d0942ff2fa79687c1307b3537..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.generalwidgets.window.rst +++ /dev/null @@ -1,45 +0,0 @@ -pyminer2.ui.generalwidgets.window package -========================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.window.applicationtest module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.applicationtest - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.mainwindow\_new module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.mainwindow_new - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmdockwidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmdockwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmmainwindow module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmmainwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.window - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.pmwidgets.rst b/docs/dts/pyminer2.ui.pmwidgets.rst deleted file mode 100644 index 843613ec32499c007fc5aecf23af21647bc9c16c..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.pmwidgets.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.pmwidgets package -============================= - -Submodules ----------- - -pyminer2.ui.pmwidgets.toplevel module -------------------------------------- - -.. automodule:: pyminer2.ui.pmwidgets.toplevel - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.pmwidgets - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.rst b/docs/dts/pyminer2.ui.rst deleted file mode 100644 index f16cf5c71335f5dc39f08850378c5214423605c1..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.rst +++ /dev/null @@ -1,33 +0,0 @@ -pyminer2.ui package -=================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base - pyminer2.ui.common - pyminer2.ui.generalwidgets - pyminer2.ui.pmwidgets - pyminer2.ui.source - -Submodules ----------- - -pyminer2.ui.pyqtsource\_rc module ---------------------------------- - -.. automodule:: pyminer2.ui.pyqtsource_rc - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.source.qss.rst b/docs/dts/pyminer2.ui.source.qss.rst deleted file mode 100644 index 84a967853e65d3fc79a2786ecaa402ca8cec2b69..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.source.qss.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyminer2.ui.source.qss package -============================== - -Submodules ----------- - -pyminer2.ui.source.qss.qss\_tools module ----------------------------------------- - -.. automodule:: pyminer2.ui.source.qss.qss_tools - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source.qss - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.ui.source.rst b/docs/dts/pyminer2.ui.source.rst deleted file mode 100644 index 2293991a056e8b8a5bc95824c2de05f607826cec..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.ui.source.rst +++ /dev/null @@ -1,18 +0,0 @@ -pyminer2.ui.source package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.source.qss - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.workspace.datamanager.rst b/docs/dts/pyminer2.workspace.datamanager.rst deleted file mode 100644 index 3de07e48ce0a19d65b6991ae7af2ba3f1bf77c46..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.workspace.datamanager.rst +++ /dev/null @@ -1,85 +0,0 @@ -pyminer2.workspace.datamanager package -====================================== - -Submodules ----------- - -pyminer2.workspace.datamanager.converter module ------------------------------------------------ - -.. automodule:: pyminer2.workspace.datamanager.converter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.datamanager module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.datamanager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.dataset module ---------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.dataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.exceptions module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.exceptions - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.historyset module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.historyset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.metadataset module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.metadataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.recyclebin module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.recyclebin - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.variable module ----------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.variable - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.varset module --------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.varset - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.workspace.datamanager - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/dts/pyminer2.workspace.rst b/docs/dts/pyminer2.workspace.rst deleted file mode 100644 index dc250a80fdfb6b5c99875721e52e2bc801d193b5..0000000000000000000000000000000000000000 --- a/docs/dts/pyminer2.workspace.rst +++ /dev/null @@ -1,18 +0,0 @@ -pyminer2.workspace package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.workspace.datamanager - -Module contents ---------------- - -.. automodule:: pyminer2.workspace - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/image/show1.jpg b/docs/image/show1.jpg deleted file mode 100644 index aa2cd6a19bc13a31d6c4b7195a48c9c785b3dc71..0000000000000000000000000000000000000000 Binary files a/docs/image/show1.jpg and /dev/null differ diff --git a/docs/image/show2.jpg b/docs/image/show2.jpg deleted file mode 100644 index 5ffd220623800a62c86c5a3afc7a14c50ce113e9..0000000000000000000000000000000000000000 Binary files a/docs/image/show2.jpg and /dev/null differ diff --git a/docs/image/show3.png b/docs/image/show3.png deleted file mode 100644 index ad1616915601f3154c69a0cc75cd52843a6ccc25..0000000000000000000000000000000000000000 Binary files a/docs/image/show3.png and /dev/null differ diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index e19d343081199815e7fe945b4990ca824f49893e..0000000000000000000000000000000000000000 --- a/docs/index.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. PyMiner documentation master file, created by - sphinx-quickstart on Wed Sep 9 22:58:12 2020. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PyMiner's documentation! -=================================== -PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。 - -User Guide ----------- - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - user/intro - user/tech - user/joinus - -API Reference ------------------ - -.. toctree:: - :maxdepth: 30 - :caption: Contents: - - user/lib_ref.rst - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 922152e96a04a242e6fc40f124261d74890617d8..0000000000000000000000000000000000000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/requirements.txt b/docs/requirements.txt similarity index 88% rename from requirements.txt rename to docs/requirements.txt index 13b78823ab943250ba6433c2aca7ca863248fd39..d91364550a18d56d58304c1e6b94e71607fe9fd8 100644 --- a/requirements.txt +++ b/docs/requirements.txt @@ -37,4 +37,8 @@ matgen>=0.1.1 QScintilla==2.11.5 yapf flake8 -configparser \ No newline at end of file +configparser +vermanager>=0.1.3 +pmgwidgets>=0.1.16 +send2trash>=1.5.0 +pytest diff --git a/docs/user/intro.rst b/docs/user/intro.rst deleted file mode 100644 index 3004214f74e082db1327d40fa5650ff5c92ca604..0000000000000000000000000000000000000000 --- a/docs/user/intro.rst +++ /dev/null @@ -1,31 +0,0 @@ -Introduction -============ - -Brief --------- -PyMiner一款基于数据工作空间的数学工具,通过加载插件的方式实现不同的需求,用易于操作的形式完成数学计算相关工作。官方网站:www.py2cn.com - -License -------- -本项目遵循GPL许可证。此外,对个人用户来说,本项目支持自由修改源码和使用,但是不支持任何未经授权许可的商用或其他盈利性行为,也不支持任何未经授权申请著作权的行为。如有违反以上许可,本项目管理团队有权进行否决。 许可解释权归属 PyMiner Development Team。 - -Cut --------- - -预览1(主界面) ->>>>>>>>>> - -.. image:: /image/show1.jpg - :scale: 40% - -预览2(表格显示) ->>>>>>>>>> - -.. image:: /image/show2.jpg - :scale: 40% - -预览3(编辑器) ->>>>>>>>>> - -.. image:: /image/show3.png - :scale: 40% \ No newline at end of file diff --git a/docs/user/joinus.rst b/docs/user/joinus.rst deleted file mode 100644 index 6b587c6b62571dd9f029e0aa2f79ca418567a0e4..0000000000000000000000000000000000000000 --- a/docs/user/joinus.rst +++ /dev/null @@ -1,42 +0,0 @@ -Join Us -============ - -Preface ------- - -为了更便于推进项目,需要了解各位擅长的工作内容,请各位群友修改自己的备注为:方向+昵称,例如pyqt_tom_coffce - -Develop Group -------------- -目前开发组已经有pyqt、算法、仿真、插件、网站、c++、项目管理多个小分队,有意向在任意领域进行参与贡献的小伙伴请直接加入小分队QQ群! - -PyMiner开发者QQ总群:945391275 - -pyqt小分队:907932713 - -算法小分队:605160230 - -仿真小分队:915736652 - -插件小分队:689417488 - -C++小分队:205591506 - -网站小分队:1131420577 - -项目管理小分队:827058366 - -产品经理/需求分析师小分队:1026801187 - - -How to Contribute:: -------------- -要真正的参与项目,除了需要了解自身特长之外,还需要了解这个项目的基本情况。在Wiki的“ 项目说明 ”我们有对项目的背景做一些介绍,在“ 项目计划 ”中我们对当前我们正在做的事情以及下一步的项目计划做了概要性描述。 - -如果你是偏产品经理和需求分析师方面的,想要为项目做些贡献,我们希望你能对matlab多一些认识,毕竟我们的目标是进行matlab替代。在此基础上,希望你能帮助我们进行需求分解,将matlab的功能模块按照重要性、优先级进行细化分解,以便我们能够更专注于细节进行实现。 - -如果你是偏qt pyqt python 方向的,想要在PyMiner的界面UI或功能方面进行参与,我们也很希望你能真正的参与到项目的代码贡献当中。在这之前你可能还需要了解我们的代码结构(在wiki的“ 开发者指南 ”中我们会有相应介绍),编码规范(在wiki的“ 编程规范 ”中)。 - -如果你是仿真方向或对Sumlink有所研究,除了项目基础信息之外,你还需要了解项目的插件系统,目前在PyMiner中,更多功能将以插件的形式进行提供。而插件我们支持使用Python或c++等多种方式进行开发。 - -如果你是算法工程师,你将是这个项目的非常重要参与者,甚至可以说,我们的未来非常依赖你们的参与,而在PyMiner中,算法工程师的贡献,也将主要通过插件的形式进行完成,为此我们需要算法工程师和其他开发者齐心协力进行合作, 由算法进行后台计算并设计输入参数和输出形式,而pyqt开发者进行插件化改造实现 ,最终将算法以插件的形式对外提供。 \ No newline at end of file diff --git a/docs/user/lib_ref.rst b/docs/user/lib_ref.rst deleted file mode 100644 index 59e8072b91d223a735767bdc8dc16edeb400edbf..0000000000000000000000000000000000000000 --- a/docs/user/lib_ref.rst +++ /dev/null @@ -1,1158 +0,0 @@ -API Reference -================= - - -app2 module -=========== - -.. automodule:: app2 - :members: - :undoc-members: - :show-inheritance: -pyminer -======= - -.. toctree:: - :maxdepth: 4 - - app2 - pmgwidgets - pyminer2 -pmgwidgets.normal package -========================= - -Submodules ----------- - -pmgwidgets.normal.value\_inputs module --------------------------------------- - -.. automodule:: pmgwidgets.normal.value_inputs - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.normal - :members: - :undoc-members: - :show-inheritance: -pmgwidgets package -================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pmgwidgets.normal - pmgwidgets.table - -Module contents ---------------- - -.. automodule:: pmgwidgets - :members: - :undoc-members: - :show-inheritance: -pmgwidgets.table package -======================== - -Submodules ----------- - -pmgwidgets.table.tableviews module ----------------------------------- - -.. automodule:: pmgwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pmgwidgets.table.tablewidgets module ------------------------------------- - -.. automodule:: pmgwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pmgwidgets.table - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.extensionlib package -======================================== - -Submodules ----------- - -pyminer2.extensions.extensionlib.baseext module ------------------------------------------------ - -.. automodule:: pyminer2.extensions.extensionlib.baseext - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.extension\_lib module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.extension_lib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensionlib.pmext module ---------------------------------------------- - -.. automodule:: pyminer2.extensions.extensionlib.pmext - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensionlib - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.extensions\_manager package -=============================================== - -Submodules ----------- - -pyminer2.extensions.extensions\_manager.ExtensionLoader module --------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.ExtensionLoader - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.UIInserter module ---------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.UIInserter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.log module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.log - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.extensions\_manager.manager module ------------------------------------------------------- - -.. automodule:: pyminer2.extensions.extensions_manager.manager - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.extensions_manager - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.package\_manager package -============================================ - -Submodules ----------- - -pyminer2.extensions.package\_manager.env\_manager module --------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.env_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_install module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_install - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_manager module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_manager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_remove module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_remove - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_setting module ------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.package_manager.package_setting - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.package\_manager.package\_update module ------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.package_manager.package_update - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.package_manager - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions package -=========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.extensionlib - pyminer2.extensions.extensions_manager - pyminer2.extensions.package_manager - pyminer2.extensions.test_demo - -Module contents ---------------- - -.. automodule:: pyminer2.extensions - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions package -================================================= - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions.test_extension - pyminer2.extensions.test_demo.extensions.test_extension2 - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions.test\_extension2 package -================================================================== - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension2.entry module ------------------------------------------------------------------------ - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.interface module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.menu module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension2.subwindow module ---------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension2 - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo.extensions.test\_extension package -================================================================= - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensions.test\_extension.entry module ----------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.entry - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.interface module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.interface - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.menu module ---------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.menu - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.extensions.test\_extension.subwindow module --------------------------------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension.subwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo.extensions.test_extension - :members: - :undoc-members: - :show-inheritance: -pyminer2.extensions.test\_demo package -====================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions.test_demo.extensions - -Submodules ----------- - -pyminer2.extensions.test\_demo.extensionlib module --------------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.extensionlib - :members: - :undoc-members: - :show-inheritance: - -pyminer2.extensions.test\_demo.mainform module ----------------------------------------------- - -.. automodule:: pyminer2.extensions.test_demo.mainform - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.extensions.test_demo - :members: - :undoc-members: - :show-inheritance: -pyminer2 package -================ - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.extensions - pyminer2.ui - pyminer2.workspace - -Submodules ----------- - -pyminer2.pmappmodern module ---------------------------- - -.. automodule:: pyminer2.pmappmodern - :members: - :undoc-members: - :show-inheritance: - -pyminer2.pmutil module ----------------------- - -.. automodule:: pyminer2.pmutil - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2 - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.base package -======================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base.widgets - -Submodules ----------- - -pyminer2.ui.base.aboutMe module -------------------------------- - -.. automodule:: pyminer2.ui.base.aboutMe - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.flow module ----------------------------- - -.. automodule:: pyminer2.ui.base.flow - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.mainForm module --------------------------------- - -.. automodule:: pyminer2.ui.base.mainForm - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.newItem module -------------------------------- - -.. automodule:: pyminer2.ui.base.newItem - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.option module ------------------------------- - -.. automodule:: pyminer2.ui.base.option - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.base.widgets package -================================ - -Submodules ----------- - -pyminer2.ui.base.widgets.consolewidget module ---------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.consolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.controlpanel module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.controlpanel - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.flowwidget module ------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.flowwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.menu\_tool\_stat\_bars module ------------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.menu_tool_stat_bars - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.notificationwidget module --------------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.notificationwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.reportwidget module --------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.reportwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.resources module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.resources - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.tablewidget module -------------------------------------------- - -.. automodule:: pyminer2.ui.base.widgets.tablewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.texteditconsolewidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.texteditconsolewidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.base.widgets.treeviews module ------------------------------------------ - -.. automodule:: pyminer2.ui.base.widgets.treeviews - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.base.widgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.common package -========================== - -Submodules ----------- - -pyminer2.ui.common.locale module --------------------------------- - -.. automodule:: pyminer2.ui.common.locale - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.openprocess module -------------------------------------- - -.. automodule:: pyminer2.ui.common.openprocess - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.platformutil module --------------------------------------- - -.. automodule:: pyminer2.ui.common.platformutil - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.common.test\_comm module ------------------------------------- - -.. automodule:: pyminer2.ui.common.test_comm - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.common - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.basicwidgets package -=============================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.basicwidgets.labels module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.labels - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.object module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.object - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons module ------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.pmpushbuttons - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.basicwidgets.toolbutton module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets.toolbutton - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.basicwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.browser package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.browser.browser module -------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser.browser - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.browser - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.containers package -============================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.containers.PMTab module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.PMTab - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.flowarea module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.containers.flowarea - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.containers.pmscrollarea module ---------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers.pmscrollarea - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.containers - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.demos\_and\_tests package -==================================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.demos\_and\_tests.qmenu\_demo module ---------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests.qmenu_demo - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.demos_and_tests - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.layouts package -========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.layouts.flowlayout module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts.flowlayout - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.layouts - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets package -================================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.generalwidgets.basicwidgets - pyminer2.ui.generalwidgets.browser - pyminer2.ui.generalwidgets.containers - pyminer2.ui.generalwidgets.demos_and_tests - pyminer2.ui.generalwidgets.layouts - pyminer2.ui.generalwidgets.sourcemgr - pyminer2.ui.generalwidgets.table - pyminer2.ui.generalwidgets.textctrls - pyminer2.ui.generalwidgets.toolbars - pyminer2.ui.generalwidgets.window - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.sourcemgr package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.sourcemgr.iconutils module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr.iconutils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.sourcemgr - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.table package -======================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.table.tableviews module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tableviews - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.table.tablewidgets module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.table.tablewidgets - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.table - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.textctrls package -============================================ - -Submodules ----------- - -pyminer2.ui.generalwidgets.textctrls.highlighter module -------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.highlighter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textctrl module ----------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textctrl - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow module --------------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls.textwidgetlineshow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.textctrls - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.toolbars package -=========================================== - -Submodules ----------- - -pyminer2.ui.generalwidgets.toolbars.toolbar module --------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars.toolbar - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.toolbars - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.generalwidgets.window package -========================================= - -Submodules ----------- - -pyminer2.ui.generalwidgets.window.applicationtest module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.applicationtest - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.mainwindow\_new module --------------------------------------------------------- - -.. automodule:: pyminer2.ui.generalwidgets.window.mainwindow_new - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmdockwidget module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmdockwidget - :members: - :undoc-members: - :show-inheritance: - -pyminer2.ui.generalwidgets.window.pmmainwindow module ------------------------------------------------------ - -.. automodule:: pyminer2.ui.generalwidgets.window.pmmainwindow - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.generalwidgets.window - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.pmwidgets package -============================= - -Submodules ----------- - -pyminer2.ui.pmwidgets.toplevel module -------------------------------------- - -.. automodule:: pyminer2.ui.pmwidgets.toplevel - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.pmwidgets - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui package -=================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.base - pyminer2.ui.common - pyminer2.ui.generalwidgets - pyminer2.ui.pmwidgets - pyminer2.ui.source - -Submodules ----------- - -pyminer2.ui.pyqtsource\_rc module ---------------------------------- - -.. automodule:: pyminer2.ui.pyqtsource_rc - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.source.qss package -============================== - -Submodules ----------- - -pyminer2.ui.source.qss.qss\_tools module ----------------------------------------- - -.. automodule:: pyminer2.ui.source.qss.qss_tools - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source.qss - :members: - :undoc-members: - :show-inheritance: -pyminer2.ui.source package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.ui.source.qss - -Module contents ---------------- - -.. automodule:: pyminer2.ui.source - :members: - :undoc-members: - :show-inheritance: -pyminer2.workspace.datamanager package -====================================== - -Submodules ----------- - -pyminer2.workspace.datamanager.converter module ------------------------------------------------ - -.. automodule:: pyminer2.workspace.datamanager.converter - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.datamanager module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.datamanager - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.dataset module ---------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.dataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.exceptions module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.exceptions - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.historyset module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.historyset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.metadataset module -------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.metadataset - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.recyclebin module ------------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.recyclebin - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.variable module ----------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.variable - :members: - :undoc-members: - :show-inheritance: - -pyminer2.workspace.datamanager.varset module --------------------------------------------- - -.. automodule:: pyminer2.workspace.datamanager.varset - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: pyminer2.workspace.datamanager - :members: - :undoc-members: - :show-inheritance: -pyminer2.workspace package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - pyminer2.workspace.datamanager - -Module contents ---------------- - -.. automodule:: pyminer2.workspace - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/user/tech.rst b/docs/user/tech.rst deleted file mode 100644 index 7c895afe9fb9449620bbb24d1d2c04beb3b60837..0000000000000000000000000000000000000000 --- a/docs/user/tech.rst +++ /dev/null @@ -1,21 +0,0 @@ -Technology -============ - -Develop Environment -------- -PyMiner项目开发环境基于Windows 10 X64,使用Python3.8+PyQt5.15+Pycharm进行技术开发, 同时,此项目支持跨平台,这意味着即使是Linux、Mac也可以直接使用或开发此软件! - -Installation -------- - -下载项目源码 ->>>>>>>>>> - -安装python并打开命令行工具,使用 pip install -r requirements.txt 导入python包,如果你的python依赖包下载太慢,我建议使用:pip install -i https://mirrors.cloud.tencent.com/pypi/simple -r requirements.txt ->>>>>>>>>>>>>>>>>>> - -调用python 执行目录下pyminer.py,例如python安装在C盘根目录下,可以在cmd命令行中执行:C:\python\python.exe C:\PyMiner\pyminer.py ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -此外,你也可以使用pyinstaller进行编译后使用,编译语句:pyinstaller -i logo.ico -w pyminer.py ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \ No newline at end of file diff --git a/docs/write.sh b/docs/write.sh deleted file mode 100644 index 078b7650f689a5802e0935a921a6967dfd89cd7e..0000000000000000000000000000000000000000 --- a/docs/write.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -cd docs - -sphinx-apidoc -o ./dts/ .. - -touch lib_ref.rst - -echo -e "API Reference\n=================\n\n" >> lib_ref.rst - - -for file in ./dts/* -do - cat $file >> lib_ref.rst -done - -mv lib_ref.rst ./user - -make html \ No newline at end of file diff --git a/logo.ico b/logo.ico deleted file mode 100644 index 3312d8606e5ccf262e3e8f3397189f9105049a19..0000000000000000000000000000000000000000 Binary files a/logo.ico and /dev/null differ diff --git a/pyminer2.bat b/pyminer2.bat deleted file mode 100644 index 9f5a4e827da05f92a6ee9193ba8c5ac770e64d8e..0000000000000000000000000000000000000000 --- a/pyminer2.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -rem 两个变量拼接,等号前后一定不要有空格 -rem pymminer_road:pyminer.bat 文件路径,默认 pyminer.bat 和 app.py 同一个路径 -set pyminer_road=%~dp0 -set app=app2.py -set pyminer_path=%pyminer_road%%app% -python %pyminer_path% diff --git a/pyminer2/extensions/tests/__init__.py b/pyminer2/extensions/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pyminer2/extensions/tests/test_demo.py b/pyminer2/extensions/tests/test_demo.py new file mode 100644 index 0000000000000000000000000000000000000000..e6d3b47f05ef8009cdbf9854508c5c0f13bbbd8d --- /dev/null +++ b/pyminer2/extensions/tests/test_demo.py @@ -0,0 +1,47 @@ +import unittest + +import numpy as np + +from Orange.data import Domain, Table, DiscreteVariable, ContinuousVariable +from Orange.util import OrangeDeprecationWarning + + +class DomainTest(unittest.TestCase): + def test_bool_raises_warning(self): + self.assertWarns(OrangeDeprecationWarning, bool, Domain([])) + self.assertWarns(OrangeDeprecationWarning, bool, + Domain([ContinuousVariable("y")])) + + def test_empty(self): + var = ContinuousVariable("y") + self.assertTrue(Domain([]).empty()) + + self.assertFalse(Domain([var]).empty()) + self.assertFalse(Domain([], [var]).empty()) + self.assertFalse(Domain([], [], [var]).empty()) + + def test_conversion(self): + a1 = DiscreteVariable("a", values=list("abc")) + a2 = DiscreteVariable("a", values=list("cab")) + b1 = DiscreteVariable("b", values=list("def")) + b2 = DiscreteVariable("b", values=list("efg")) + c1 = ContinuousVariable("c") + c2 = DiscreteVariable("c", values=list("efg")) + dom1 = Domain([a1, b1, c1]) + dom2 = Domain([a2, b2, c2]) + + data1 = Table.from_numpy( + dom1, np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])) + np.testing.assert_array_equal( + data1.transform(dom2), + [[1, np.nan, np.nan], [2, 0, np.nan], [0, 1, np.nan]]) + + data2 = Table.from_numpy( + dom2, np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])) + np.testing.assert_array_equal( + data2.transform(dom1), + [[2, 1, np.nan], [0, 2, np.nan], [1, np.nan, np.nan]]) + + +if __name__ == "__main__": + unittest.main() diff --git "a/pyminer2/output/class-\347\273\223\346\236\234.html" "b/pyminer2/output/class-\347\273\223\346\236\234.html" deleted file mode 100644 index 9ae791943b5922b2db6adb1cd490ba8ad7dac0b3..0000000000000000000000000000000000000000 --- "a/pyminer2/output/class-\347\273\223\346\236\234.html" +++ /dev/null @@ -1,1324 +0,0 @@ - - - - - -结果: class - - - -
-

结果: class

-
-
-

CONTENTS PROCEDURE

-
-

Contents 过程

-
-

WORK.IMPORT

-
-

属性

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
数据集名WORK.IMPORT观测19
成员类型DATA变量5
引擎V9索引0
创建时间2020-04-07 13:47:09观测长度32
上次修改时间2020-04-07 13:47:09删除的观测0
保护 已压缩NO
数据集类型 已排序NO
标签   
数据表示法SOLARIS_X86_64, LINUX_X86_64, ALPHA_TRU64, LINUX_IA64  
编码utf-8 Unicode (UTF-8)  
-
-
-

引擎/主机信息

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
引擎/主机相关信息
数据集页面大小65536
数据集页数1
首数据页1
每页最大观测数2038
首数据页的观测数19
数据集修复数0
文件名/tmp/SAS_work05AC000009FD_localhost.localdomain/SAS_work6448000009FD_localhost.localdomain/import.sas7bdat
创建版本9.0401M6
创建主机Linux
Inode 号671605
访问权限rw-rw-r--
所有者名sasdemo
文件大小128KB
文件大小(字节)131072
-
-
-

变量

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
按字母排序的变量和属性列表
#变量类型长度输出格式输入格式
3Age数值8BEST12.BEST32.
4Height数值8BEST12.BEST32.
1Name字符7$7.$7.
2Sex字符1$1.$1.
5Weight数值8BEST12.BEST32.
-
-
-
-
- - diff --git a/pyminer2/output/data.png b/pyminer2/output/data.png deleted file mode 100644 index eb4db227ce96e2e8a7e8f7095cbc500ab343f2d9..0000000000000000000000000000000000000000 Binary files a/pyminer2/output/data.png and /dev/null differ diff --git a/pyminer2/output/demo.html b/pyminer2/output/demo.html deleted file mode 100644 index c0ce4efc54f79a8c1514e6e51c6e621d69eba14b..0000000000000000000000000000000000000000 --- a/pyminer2/output/demo.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - Document - - - - - zheshiyizhangzhaopian - CLASS.csv -
-

描述性统计量:Age

- -
- -

统计量

- - - - - - - - - - - - - - -
- Company - Address
row - 1, cell 1row - 1, cell 2
row 2, cell 2
- - - \ No newline at end of file diff --git a/pyminer2/output/demo2.html b/pyminer2/output/demo2.html deleted file mode 100644 index 54cdecd1061d0c7d81f81d4d5f0528c38fbf685b..0000000000000000000000000000000000000000 --- a/pyminer2/output/demo2.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - Document - - - - - - zheshiyizhangzhaopian - dataset_name -
-

header

- -
- -

title

- - - - """ th""" - - - """td """ -
- - - \ No newline at end of file diff --git a/pyminer2/output/demo3.html b/pyminer2/output/demo3.html deleted file mode 100644 index bd6d884420b311e4871e91e05ada8671e6a72464..0000000000000000000000000000000000000000 --- a/pyminer2/output/demo3.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - Document - - - - - zheshiyizhangzhaopian - CLASS.csv -
-

描述性统计量:Age

- -
- -

统计量

- - - - - - - - - - - - - - -
- Company - Address
Age23
SexM
- - - - diff --git a/pyminer2/output/features_detail.csv b/pyminer2/output/features_detail.csv deleted file mode 100644 index 4cf2af38a2bc57f31dd2b9cad78c9b0031bdc6bf..0000000000000000000000000000000000000000 --- a/pyminer2/output/features_detail.csv +++ /dev/null @@ -1,206 +0,0 @@ -var_name,split_list,sub_total_sample_num,positive_sample_num,negative_sample_num,sub_total_num_percentage,positive_rate_in_sub_total,woe_list,iv_list,iv -LIMIT_BAL,"(-INF,20000.0]",2471,895,1576,0.08236666666666667,0.3622015378389316,0.6928654999869586,0.046710367157150254,0.17832042746712123 -LIMIT_BAL,"(20000.0,30000.0]",1610,568,1042,0.05366666666666667,0.3527950310559006,0.6519112803447412,0.02672524264441017,0.17832042746712123 -LIMIT_BAL,"(30000.0,50000.0]",3595,977,2618,0.11983333333333333,0.2717663421418637,0.2730077735798462,0.009602918871899211,0.17832042746712123 -LIMIT_BAL,"(50000.0,70000.0]",1556,443,1113,0.051866666666666665,0.2847043701799486,0.3374425585058087,0.006451801333305745,0.17832042746712123 -LIMIT_BAL,"(70000.0,80000.0]",1567,363,1204,0.05223333333333333,0.23165283982131463,0.05968540467153012,0.0001891649163997143,0.17832042746712123 -LIMIT_BAL,"(80000.0,140000.0]",4491,1076,3415,0.1497,0.2395902916945001,0.10376003622092636,0.0016581726994202022,0.17832042746712123 -LIMIT_BAL,"(140000.0,240000.0]",7643,1326,6317,0.25476666666666664,0.1734920842601073,-0.30239045671854825,0.021334869830481214,0.17832042746712123 -LIMIT_BAL,"(240000.0,360000.0]",4591,694,3897,0.15303333333333333,0.1511653234589414,-0.4668032225505958,0.02904168897172901,0.17832042746712123 -LIMIT_BAL,"(360000.0,+INF)",2476,294,2182,0.08253333333333333,0.11873990306946688,-0.7457301008979865,0.036606201042325696,0.17832042746712123 -SEX,"(-INF,1.0]",11888,2873,9015,0.39626666666666666,0.2416722745625841,0.11515395090593507,0.005422774138995026,0.009179579035859246 -SEX,"(1.0,2.0]",18112,3763,14349,0.6037333333333333,0.20776280918727916,-0.07977671829968996,0.0037568048968642208,0.009179579035859246 -EDUCATION,"(-INF,1.0]",10599,2036,8563,0.3533,0.19209359373525806,-0.1777764560681515,0.010611953168794923,0.0362843855480741 -EDUCATION,"(1.0,2.0]",14030,3330,10700,0.4676666666666667,0.23734853884533144,0.0914155870585923,0.004007549938437168,0.0362843855480741 -EDUCATION,"(2.0,3.0]",4917,1237,3680,0.1639,0.2515761643278422,0.16846339874620386,0.004868627435992278,0.0362843855480741 -EDUCATION,"(3.0,+INF)",454,33,421,0.015133333333333334,0.07268722466960352,-1.2874354755972601,0.016796255004849738,0.0362843855480741 -MARRIAGE,"(-INF,1.0]",13713,3211,10502,0.4571,0.2341573689200029,0.07370372536252413,0.002533999682152041,0.005648854093842209 -MARRIAGE,"(1.0,2.0]",15964,3341,12623,0.5321333333333333,0.20928338762214985,-0.07056335753712935,0.002597414865025217,0.005648854093842209 -MARRIAGE,"(2.0,+INF)",323,84,239,0.010766666666666667,0.26006191950464397,0.21304102282719534,0.0005174395466649514,0.005648854093842209 -AGE,"(-INF,29.0]",9618,2197,7421,0.3206,0.22842586816385943,0.04146601030568126,0.0005576158191264353,0.007733950791700712 -AGE,"(29.0,35.0]",7191,1400,5791,0.2397,0.19468780419969406,-0.16114569361218078,0.005944580932289207,0.007733950791700712 -AGE,"(35.0,+INF)",13191,3039,10152,0.4397,0.2303843529679327,0.05254481042771908,0.0012317540402850696,0.007733950791700712 -PAY_0,"(-INF,-2.0]",2759,365,2394,0.09196666666666667,0.13229430953243929,-0.6221362964840905,0.029528023666821907,0.8739783653128863 -PAY_0,"(-2.0,-1.0]",5686,954,4732,0.18953333333333333,0.16778051354203308,-0.3427524661110419,0.02014441928877883,0.8739783653128863 -PAY_0,"(-1.0,0.0]",14737,1888,12849,0.49123333333333336,0.12811291307593134,-0.6590608705447762,0.1749410436214079,0.8739783653128863 -PAY_0,"(0.0,1.0]",3688,1252,2436,0.12293333333333334,0.33947939262472887,0.5930719655014198,0.050058188440655065,0.8739783653128863 -PAY_0,"(1.0,2.0]",2667,1844,823,0.0889,0.6914135733033371,2.065423140012592,0.5011813649341148,0.8739783653128863 -PAY_0,"(2.0,+INF)",463,333,130,0.015433333333333334,0.7192224622030238,2.199294574444508,0.09812532536110787,0.8739783653128863 -PAY_2,"(-INF,-2.0]",3782,691,3091,0.12606666666666666,0.18270756213643574,-0.23942300214878096,0.006744198239828771,0.5442604545006664 -PAY_2,"(-2.0,-1.0]",6050,966,5084,0.20166666666666666,0.1596694214876033,-0.4020027103968497,0.02895629343296965,0.5442604545006664 -PAY_2,"(-1.0,0.0]",15730,2503,13227,0.5243333333333333,0.15912269548633184,-0.40608314635264464,0.07672628911456658,0.5442604545006664 -PAY_2,"(0.0,2.0]",3955,2189,1766,0.13183333333333333,0.5534766118836916,1.4734147092666419,0.374661407807037,0.5442604545006664 -PAY_2,"(2.0,+INF)",483,287,196,0.0161,0.5942028985507246,1.6400543986070122,0.05717226590626434,0.5442604545006664 -PAY_3,"(-INF,-2.0]",4085,757,3328,0.13616666666666666,0.18531211750305998,-0.2220764426014745,0.006299555430960642,0.4140747794233897 -PAY_3,"(-2.0,-1.0]",5938,926,5012,0.19793333333333332,0.1559447625463119,-0.4300289894806746,0.03224192166630144,0.4140747794233897 -PAY_3,"(-1.0,0.0]",15764,2751,13013,0.5254666666666666,0.17451154529307283,-0.2952973433365235,0.04205359354076571,0.4140747794233897 -PAY_3,"(0.0,2.0]",3823,1970,1853,0.12743333333333334,0.5153021187549045,1.31991459609142,0.2871547364233054,0.4140747794233897 -PAY_3,"(2.0,+INF)",390,232,158,0.013,0.5948717948717949,1.6428291406124058,0.04632497236205653,0.4140747794233897 -PAY_4,"(-INF,-2.0]",4348,837,3511,0.14493333333333333,0.1925022999080037,-0.17514501083669975,0.004228651399304983,0.3633261381585188 -PAY_4,"(-2.0,-1.0]",5687,904,4783,0.18956666666666666,0.1589590293652189,-0.4073067897261726,0.02789644396773778,0.3633261381585188 -PAY_4,"(-1.0,0.0]",16455,3016,13439,0.5485,0.1832877544819204,-0.23554244785388423,0.028432445797279063,0.3633261381585188 -PAY_4,"(0.0,2.0]",3161,1654,1507,0.10536666666666666,0.5232521354001898,1.3517626749094978,0.2497322107949585,0.3633261381585188 -PAY_4,"(2.0,+INF)",349,225,124,0.011633333333333334,0.6446991404011462,1.854505478442306,0.053036386199238464,0.3633261381585188 -PAY_5,"(-INF,-2.0]",4546,895,3651,0.15153333333333333,0.1968763748350198,-0.14724557518883513,0.0031504126832441574,0.3376218561900382 -PAY_5,"(-2.0,-1.0]",5539,897,4642,0.18463333333333334,0.1619425889149666,-0.38515763098544586,0.024461334782051414,0.3376218561900382 -PAY_5,"(-1.0,0.0]",16947,3195,13752,0.5649,0.18852894317578334,-0.20091015237395057,0.021524126290472047,0.3376218561900382 -PAY_5,"(0.0,2.0]",2626,1423,1203,0.08753333333333334,0.5418888042650419,1.4266358731135886,0.23246596040772818,0.3376218561900382 -PAY_5,"(2.0,+INF)",342,226,116,0.0114,0.6608187134502924,1.9256313924249704,0.056020022026542396,0.3376218561900382 -PAY_6,"(-INF,-2.0]",4895,981,3914,0.16316666666666665,0.2004085801838611,-0.1250556081533095,0.0024626770221397114,0.2918168990854765 -PAY_6,"(-2.0,-1.0]",5740,975,4765,0.19133333333333333,0.16986062717770034,-0.327928259662852,0.01869859146725299,0.2918168990854765 -PAY_6,"(-1.0,0.0]",16286,3069,13217,0.5428666666666667,0.18844406238487044,-0.20146507527031587,0.020795619887741486,0.2918168990854765 -PAY_6,"(0.0,2.0]",2766,1401,1365,0.0922,0.5065075921908894,1.2847188406853263,0.19617393703761246,0.2918168990854765 -PAY_6,"(2.0,+INF)",313,210,103,0.010433333333333333,0.670926517571885,1.9710650516547454,0.05368607367072983,0.2918168990854765 -BILL_AMT1,"(-INF,780.0]",4469,1104,3365,0.14896666666666666,0.24703513090176774,0.14419904947010154,0.0032214493555986165,0.018378340546571243 -BILL_AMT1,"(780.0,2187.75]",1819,346,1473,0.06063333333333333,0.1902144035184167,-0.18993041642640215,0.0020713540151488068,0.018378340546571243 -BILL_AMT1,"(2187.75,5975.46]",2673,556,2117,0.0891,0.20800598578376356,-0.07829984041497355,0.0005343228863983925,0.018378340546571243 -BILL_AMT1,"(5975.46,12545.199999999999]",2782,608,2174,0.09273333333333333,0.21854780733285406,-0.015462063389611319,2.207466099629454e-05,0.018378340546571243 -BILL_AMT1,"(12545.199999999999,18243.59]",1955,517,1438,0.06516666666666666,0.2644501278772379,0.2357214639598541,0.0038565703096126477,0.018378340546571243 -BILL_AMT1,"(18243.59,25483.0]",1985,460,1525,0.06616666666666667,0.23173803526448364,0.06016395610900582,0.00024351481155193157,0.018378340546571243 -BILL_AMT1,"(25483.0,34699.2]",1984,506,1478,0.06613333333333334,0.2550403225806452,0.18677870159862595,0.0024264511624719595,0.018378340546571243 -BILL_AMT1,"(34699.2,52204.899999999994]",3333,728,2605,0.1111,0.21842184218421842,-0.016199803166003755,2.9024652479778423e-05,0.018378340546571243 -BILL_AMT1,"(52204.899999999994,70590.77]",1860,376,1484,0.062,0.2021505376344086,-0.11422007791559731,0.000783078167233739,0.018378340546571243 -BILL_AMT1,"(70590.77,90884.88]",1650,370,1280,0.055,0.22424242424242424,0.017574844719708858,1.7071344143437295e-05,0.018378340546571243 -BILL_AMT1,"(90884.88,151604.14]",2800,523,2277,0.09333333333333334,0.18678571428571428,-0.21234545086181555,0.003959197633587194,0.018378340546571243 -BILL_AMT1,"(151604.14,+INF)",2690,542,2148,0.08966666666666667,0.20148698884758365,-0.1183393123923502,0.0012142315473484455,0.018378340546571243 -BILL_AMT2,"(-INF,316.0]",3786,874,2912,0.1262,0.23085050184891706,0.05517205026463414,0.00039004792664562083,0.018659633044395916 -BILL_AMT2,"(316.0,1050.0]",1681,405,1276,0.05603333333333333,0.2409280190362879,0.11108877559531562,0.0007128362581941757,0.018659633044395916 -BILL_AMT2,"(1050.0,2564.2400000000016]",1704,364,1340,0.0568,0.2136150234741784,-0.04458382135997738,0.00011149796156301207,0.018659633044395916 -BILL_AMT2,"(2564.2400000000016,6277.150000000001]",2219,404,1815,0.07396666666666667,0.18206399278954483,-0.24373867245963157,0.004095676629020637,0.018659633044395916 -BILL_AMT2,"(6277.150000000001,10320.550000000001]",1815,393,1422,0.0605,0.21652892561983472,-0.027322810514651793,4.482121302353375e-05,0.018659633044395916 -BILL_AMT2,"(10320.550000000001,15073.34]",1507,356,1151,0.05023333333333333,0.23623092236230922,0.08523151999788034,0.000373566450915649,0.018659633044395916 -BILL_AMT2,"(15073.34,21015.199999999997]",2243,587,1656,0.07476666666666666,0.26170307623718236,0.2215515987040216,0.0038945754115734354,0.018659633044395916 -BILL_AMT2,"(21015.199999999997,27689.5]",1549,371,1178,0.05163333333333334,0.2395093608779858,0.10331588689787088,0.0005669702148337187,0.018659633044395916 -BILL_AMT2,"(27689.5,35137.0]",1549,393,1156,0.05163333333333334,0.2537120723047127,0.17977573443451061,0.0017518434841291173,0.018659633044395916 -BILL_AMT2,"(35137.0,45008.12]",1507,304,1203,0.05023333333333333,0.20172528201725282,-0.11685876489679417,0.0006636094717620058,0.018659633044395916 -BILL_AMT2,"(45008.12,51259.8]",1602,384,1218,0.0534,0.2397003745318352,0.1043642864825792,0.000598499011556531,0.018659633044395916 -BILL_AMT2,"(51259.8,68779.76000000001]",1794,360,1434,0.0598,0.20066889632107024,-0.12343177781681054,0.0008796881493496996,0.018659633044395916 -BILL_AMT2,"(68779.76000000001,92998.54999999997]",1944,442,1502,0.0648,0.2273662551440329,0.035444213269907265,8.221154167381903e-05,0.018659633044395916 -BILL_AMT2,"(92998.54999999997,157375.5]",2754,514,2240,0.0918,0.18663761801016704,-0.21332072563440158,0.00392887380381994,0.018659633044395916 -BILL_AMT2,"(157375.5,+INF)",2346,485,1861,0.0782,0.20673486786018755,-0.08603320940390685,0.0005649155163350227,0.018659633044395916 -BILL_AMT3,"(-INF,390.0]",4583,1080,3503,0.15276666666666666,0.23565350207287802,0.08202836481627225,0.0010513687056525917,0.01772831601082556 -BILL_AMT3,"(390.0,2771.25]",2977,638,2339,0.09923333333333334,0.21430970775948943,-0.040453365403037206,0.00016056010127588597,0.01772831601082556 -BILL_AMT3,"(2771.25,7543.16]",2520,450,2070,0.084,0.17857142857142858,-0.26736912573216465,0.00555750714731324,0.01772831601082556 -BILL_AMT3,"(7543.16,12149.22]",1903,431,1472,0.06343333333333333,0.22648449816079874,0.030417958748545228,5.918923048802768e-05,0.01772831601082556 -BILL_AMT3,"(12149.22,20110.4]",3027,758,2269,0.1009,0.25041295011562603,0.1622759925662298,0.002776579199750066,0.01772831601082556 -BILL_AMT3,"(20110.4,26700.0]",1630,370,1260,0.05433333333333333,0.22699386503067484,0.033323200447768875,6.0893779167372144e-05,0.01772831601082556 -BILL_AMT3,"(26700.0,35891.020000000004]",2070,541,1529,0.069,0.2613526570048309,0.21973719620792895,0.00353391569102391,0.01772831601082556 -BILL_AMT3,"(35891.020000000004,47397.0]",1800,414,1386,0.06,0.23,0.050375967321125495,0.00015440017364363036,0.01772831601082556 -BILL_AMT3,"(47397.0,59350.08]",1885,389,1496,0.06283333333333334,0.20636604774535808,-0.08828362084165316,0.0004776559390607437,0.01772831601082556 -BILL_AMT3,"(59350.08,76777.40000000001]",1605,365,1240,0.0535,0.22741433021806853,0.03571789216068086,6.893270060001284e-05,0.01772831601082556 -BILL_AMT3,"(76777.40000000001,101471.8]",1704,354,1350,0.0568,0.20774647887323944,-0.07987574603707144,0.00035431301569636715,0.01772831601082556 -BILL_AMT3,"(101471.8,176413.69]",2556,483,2073,0.0852,0.18896713615023475,-0.1980482961332917,0.0031571719780055566,0.01772831601082556 -BILL_AMT3,"(176413.69,+INF)",1740,363,1377,0.058,0.20862068965517241,-0.07457245775352216,0.0003158283491481558,0.01772831601082556 -BILL_AMT4,"(-INF,10.599999999999909]",3874,899,2975,0.12913333333333332,0.23205988642230252,0.06197079796300919,0.000504475690401007,0.023391172987145444 -BILL_AMT4,"(10.599999999999909,671.8000000000002]",1507,375,1132,0.05023333333333333,0.24883875248838752,0.15387194938455973,0.0012401077055545304,0.023391172987145444 -BILL_AMT4,"(671.8000000000002,2500.0]",2327,502,1825,0.07756666666666667,0.21572840567253976,-0.03204799806634944,7.895451271217689e-05,0.023391172987145444 -BILL_AMT4,"(2500.0,7660.0]",2679,450,2229,0.0893,0.167973124300112,-0.3413735694126076,0.00941891963832681,0.023391172987145444 -BILL_AMT4,"(7660.0,10892.5]",1533,331,1202,0.0511,0.21591650358773645,-0.030936516948139342,4.8484137907441535e-05,0.023391172987145444 -BILL_AMT4,"(10892.5,15516.0]",1533,333,1200,0.0511,0.2172211350293542,-0.023247124978857604,2.7436854225382676e-05,0.023391172987145444 -BILL_AMT4,"(15516.0,22053.2]",2805,746,2059,0.0935,0.2659536541889483,0.24343698250682003,0.005913107795098066,0.023391172987145444 -BILL_AMT4,"(22053.2,28279.37]",1603,369,1234,0.05343333333333333,0.23019338739862757,0.051467633390458414,0.00014356890305680442,0.023391172987145444 -BILL_AMT4,"(28279.37,35324.0]",1669,423,1246,0.05563333333333333,0.2534451767525464,0.17836563969851718,0.0018573785426929793,0.023391172987145444 -BILL_AMT4,"(35324.0,46885.4]",1701,371,1330,0.0567,0.21810699588477367,-0.018044960404723892,1.836977436236372e-05,0.023391172987145444 -BILL_AMT4,"(46885.4,57583.0]",1570,361,1209,0.052333333333333336,0.22993630573248408,0.050016305863242405,0.00013274205415199713,0.023391172987145444 -BILL_AMT4,"(57583.0,77068.72]",1722,358,1364,0.0574,0.20789779326364694,-0.07895664213705261,0.0003499549439025481,0.023391172987145444 -BILL_AMT4,"(77068.72,101181.63999999998]",1590,350,1240,0.053,0.22012578616352202,-0.006246295196671517,2.0642575072016345e-06,0.023391172987145444 -BILL_AMT4,"(101181.63999999998,171576.6]",2332,432,1900,0.07773333333333333,0.18524871355060035,-0.22249639421067954,0.003609386167509546,0.023391172987145444 -BILL_AMT4,"(171576.6,+INF)",1555,336,1219,0.051833333333333335,0.21607717041800642,-0.029987750083650302,4.622200973658621e-05,0.023391172987145444 -BILL_AMT5,"(-INF,390.0]",5190,1251,3939,0.173,0.24104046242774566,0.11170340589476413,0.0022256326212243406,0.027977048006212226 -BILL_AMT5,"(390.0,2782.6000000000004]",3263,667,2596,0.10876666666666666,0.20441311676371438,-0.10024991665426643,0.0010625231505511047,0.027977048006212226 -BILL_AMT5,"(2782.6000000000004,8228.68]",2670,433,2237,0.089,0.16217228464419475,-0.3834660433936455,0.01169396189361385,0.027977048006212226 -BILL_AMT5,"(8228.68,12429.0]",1874,415,1459,0.06246666666666666,0.2214514407684098,0.0014591479815104736,1.3305269938543584e-07,0.027977048006212226 -BILL_AMT5,"(12429.0,17577.72]",1741,422,1319,0.05803333333333333,0.24238943136128663,0.11906332632035008,0.0008498933301178189,0.027977048006212226 -BILL_AMT5,"(17577.72,20100.0]",1601,427,1174,0.053366666666666666,0.26670830730793255,0.24729916570358576,0.0034863635906150375,0.027977048006212226 -BILL_AMT5,"(20100.0,28357.16]",2191,524,1667,0.07303333333333334,0.23916020082154268,0.10139793627178874,0.0007720598660991613,0.027977048006212226 -BILL_AMT5,"(28357.16,35540.92]",1721,444,1277,0.05736666666666667,0.2579895409645555,0.20224285716621768,0.00247768729413572,0.027977048006212226 -BILL_AMT5,"(35540.92,52319.96000000001]",2549,592,1957,0.08496666666666666,0.23224794036877205,0.06302578915808008,0.00034342980947267473,0.027977048006212226 -BILL_AMT5,"(52319.96000000001,77582.88]",2140,414,1726,0.07133333333333333,0.19345794392523363,-0.16900871035975554,0.0019414614802653622,0.027977048006212226 -BILL_AMT5,"(77582.88,104116.46]",1614,353,1261,0.0538,0.21871127633209417,-0.014505071197817142,1.1273576708758259e-05,0.027977048006212226 -BILL_AMT5,"(104116.46,165339.62]",1934,357,1577,0.06446666666666667,0.18459152016546018,-0.2268565846330677,0.0031078274058677887,0.027977048006212226 -BILL_AMT5,"(165339.62,+INF)",1512,337,1175,0.0504,0.22288359788359788,0.009746719253448864,4.800934841225915e-06,0.027977048006212226 -BILL_AMT6,"(-INF,441.0]",5945,1374,4571,0.19816666666666666,0.23111858704793944,0.05668124920356561,0.0006467093973348092,0.025327696085718124 -BILL_AMT6,"(441.0,1263.96]",1580,311,1269,0.05266666666666667,0.19683544303797468,-0.1475043089441355,0.0010987208439780579,0.025327696085718124 -BILL_AMT6,"(1263.96,2757.0]",1519,326,1193,0.050633333333333336,0.21461487820934824,-0.03864181395521771,7.479014057184353e-05,0.025327696085718124 -BILL_AMT6,"(2757.0,5854.900000000001]",1693,263,1430,0.056433333333333335,0.1553455404607206,-0.43458837692832664,0.00937535491699691,0.025327696085718124 -BILL_AMT6,"(5854.900000000001,12252.200000000004]",2763,564,2199,0.0921,0.20412595005428882,-0.10201660337710369,0.0009312267837737518,0.025327696085718124 -BILL_AMT6,"(12252.200000000004,17105.08]",1511,367,1144,0.050366666666666664,0.242885506287227,0.12176286503163523,0.0007720000127349943,0.025327696085718124 -BILL_AMT6,"(17105.08,19924.0]",1554,431,1123,0.0518,0.27734877734877733,0.30103628218651285,0.005082508544548316,0.025327696085718124 -BILL_AMT6,"(19924.0,27447.98]",1938,460,1478,0.0646,0.23735810113519093,0.09146854155714257,0.0005542226905597132,0.025327696085718124 -BILL_AMT6,"(27447.98,34433.44]",1862,489,1373,0.062066666666666666,0.26262083780880774,0.2262962192225132,0.003377099430791705,0.025327696085718124 -BILL_AMT6,"(34433.44,51296.72999999998]",2540,591,1949,0.08466666666666667,0.2326771653543307,0.0654314396447637,0.0003690824048290131,0.025327696085718124 -BILL_AMT6,"(51296.72999999998,69433.52]",1561,299,1262,0.052033333333333334,0.19154388212684176,-0.18132221065180215,0.0016241845098430327,0.025327696085718124 -BILL_AMT6,"(69433.52,114557.57]",2601,572,2029,0.0867,0.21991541714725105,-0.0074722190563535126,4.8307270571272815e-06,0.025327696085718124 -BILL_AMT6,"(114557.57,+INF)",2933,589,2344,0.09776666666666667,0.200818274803955,-0.12250083607829446,0.0014169656826988517,0.025327696085718124 -PAY_AMT1,"(-INF,17.0]",5404,1938,3466,0.18013333333333334,0.35862324204293117,0.6773423487729091,0.09733106427046086,0.18635150586363766 -PAY_AMT1,"(17.0,991.0]",2065,434,1631,0.06883333333333333,0.21016949152542372,-0.06521689556810054,0.000287436772086129,0.18635150586363766 -PAY_AMT1,"(991.0,1450.0]",2623,590,2033,0.08743333333333334,0.2249332825009531,0.021541847424403994,4.081710922093427e-05,0.18635150586363766 -PAY_AMT1,"(1450.0,1652.0]",1516,368,1148,0.05053333333333333,0.24274406332453827,0.12099354977036753,0.0007646407830682841,0.18635150586363766 -PAY_AMT1,"(1652.0,2000.0]",2807,642,2165,0.09356666666666667,0.22871392946205915,0.043099776677088183,0.00017589495133043804,0.18635150586363766 -PAY_AMT1,"(2000.0,2494.62]",1589,305,1284,0.05296666666666667,0.1919446192573946,-0.17873645380544825,0.0016077182726246535,0.18635150586363766 -PAY_AMT1,"(2494.62,3082.0]",2374,512,1862,0.07913333333333333,0.21566975568660487,-0.032394687340850215,8.22933345532727e-05,0.18635150586363766 -PAY_AMT1,"(3082.0,3803.16]",1513,352,1161,0.05043333333333333,0.232650363516193,0.06528139570829875,0.00021883496361759395,0.18635150586363766 -PAY_AMT1,"(3803.16,4878.200000000004]",1746,338,1408,0.0582,0.19358533791523483,-0.16819241254988446,0.0015691250304494407,0.18635150586363766 -PAY_AMT1,"(4878.200000000004,17451.32]",6774,1003,5771,0.2258,0.14806613522291112,-0.49116278052629314,0.04708220532437612,0.18635150586363766 -PAY_AMT1,"(17451.32,+INF)",1589,154,1435,0.05296666666666667,0.09691629955947137,-0.9732799422661976,0.037191475051849936,0.18635150586363766 -PAY_AMT2,"(-INF,100.0]",5696,1895,3801,0.18986666666666666,0.33268960674157305,0.5626416788387243,0.06913595756634253,0.1665492471442373 -PAY_AMT2,"(100.0,696.0]",1504,336,1168,0.050133333333333335,0.22340425531914893,0.012750212427465352,8.179036354475957e-06,0.1665492471442373 -PAY_AMT2,"(696.0,1191.0]",1896,437,1459,0.0632,0.23048523206751054,0.05311381071550158,0.00018092876238988024,0.1665492471442373 -PAY_AMT2,"(1191.0,1600.0]",3012,761,2251,0.1004,0.25265604249667994,0.1741906077861551,0.003193388230299325,0.1665492471442373 -PAY_AMT2,"(1600.0,2000.0]",2785,616,2169,0.09283333333333334,0.22118491921005387,-8.742721003511829e-05,7.095559218494552e-10,0.1665492471442373 -PAY_AMT2,"(2000.0,2485.0]",1606,307,1299,0.053533333333333336,0.19115815691158156,-0.18381501648298276,0.0017160118389221491,0.1665492471442373 -PAY_AMT2,"(2485.0,3500.0]",3308,734,2574,0.11026666666666667,0.2218863361547763,0.003979741698043052,1.7483791120266115e-06,0.1665492471442373 -PAY_AMT2,"(3500.0,4819.810000000001]",2093,419,1674,0.06976666666666667,0.2001911132345915,-0.12641314835111694,0.0010755525775343986,0.1665492471442373 -PAY_AMT2,"(4819.810000000001,6587.74]",2651,415,2236,0.08836666666666666,0.15654470011316485,-0.42547811395331847,0.0141110269761465,0.1665492471442373 -PAY_AMT2,"(6587.74,9842.3]",1843,314,1529,0.06143333333333333,0.17037438958220294,-0.32428896310187877,0.0058777015166803824,0.1665492471442373 -PAY_AMT2,"(9842.3,15004.24]",1662,238,1424,0.0554,0.14320096269554752,-0.5302670645073192,0.01330094226575454,0.1665492471442373 -PAY_AMT2,"(15004.24,+INF)",1944,164,1780,0.0648,0.08436213991769548,-1.1258146580359296,0.05794780928514518,0.1665492471442373 -PAY_AMT3,"(-INF,0.0]",5968,1931,4037,0.19893333333333332,0.32355898123324395,0.5212231924412071,0.061609292364441515,0.13721431130222167 -PAY_AMT3,"(0.0,495.0]",1885,425,1460,0.06283333333333334,0.22546419098143236,0.024584624872841077,3.8236865228467585e-05,0.13721431130222167 -PAY_AMT3,"(495.0,1000.0]",2941,702,2239,0.09803333333333333,0.23869432165929955,0.09883588906425843,0.000983954362671625,0.13721431130222167 -PAY_AMT3,"(1000.0,1294.2200000000003]",1555,322,1233,0.051833333333333335,0.20707395498392284,-0.08396672431411062,0.00035688210148408534,0.13721431130222167 -PAY_AMT3,"(1294.2200000000003,1600.0]",1906,475,1431,0.06353333333333333,0.24921301154249736,0.1558731689731493,0.0016103571087707359,0.13721431130222167 -PAY_AMT3,"(1600.0,2194.0]",3069,648,2421,0.1023,0.21114369501466276,-0.059358143720188196,0.0003544724856445453,0.13721431130222167 -PAY_AMT3,"(2194.0,2906.1800000000003]",1578,357,1221,0.0526,0.2262357414448669,0.02899750973072625,4.458634298384775e-05,0.13721431130222167 -PAY_AMT3,"(2906.1800000000003,3280.42]",1569,266,1303,0.0523,0.16953473550031867,-0.3302409652994701,0.005179882720073522,0.13721431130222167 -PAY_AMT3,"(3280.42,4574.949999999997]",2079,432,1647,0.0693,0.2077922077922078,-0.07959796731866271,0.0004293194343114696,0.13721431130222167 -PAY_AMT3,"(4574.949999999997,5485.6]",1598,226,1372,0.053266666666666664,0.1414267834793492,-0.5448024355721962,0.013438178599739536,0.13721431130222167 -PAY_AMT3,"(5485.6,9000.0]",2397,420,1977,0.0799,0.17521902377972465,-0.2903939205298164,0.006193001735238925,0.13721431130222167 -PAY_AMT3,"(9000.0,16724.97]",1890,268,1622,0.063,0.14179894179894179,-0.5417409388326572,0.015730671760604262,0.13721431130222167 -PAY_AMT3,"(16724.97,+INF)",1565,164,1401,0.05216666666666667,0.1047923322683706,-0.8863875762846168,0.03124547542102912,0.13721431130222167 -PAY_AMT4,"(-INF,0.0]",6408,1993,4415,0.2136,0.3110174781523096,0.4633202385501562,0.051597938819876184,0.11576960255147234 -PAY_AMT4,"(0.0,435.0]",2149,444,1705,0.07163333333333333,0.20660772452303397,-0.08680865686135236,0.0005267316072138836,0.11576960255147234 -PAY_AMT4,"(435.0,900.0]",2515,610,1905,0.08383333333333333,0.24254473161033796,0.11990878489739636,0.0012455117262395999,0.11576960255147234 -PAY_AMT4,"(900.0,1197.0]",2634,604,2030,0.0878,0.22930903568716782,0.04647024605066463,0.00019205639288691706,0.11576960255147234 -PAY_AMT4,"(1197.0,1606.0]",1805,461,1344,0.06016666666666667,0.2554016620498615,0.18867966827837565,0.002253811516464865,0.11576960255147234 -PAY_AMT4,"(1606.0,2005.0]",2192,476,1716,0.07306666666666667,0.21715328467153286,-0.023646270157667744,4.058549069373825e-05,0.11576960255147234 -PAY_AMT4,"(2005.0,2716.36]",1651,327,1324,0.05503333333333333,0.1980617807389461,-0.1397653314681825,0.0010331027323468099,0.11576960255147234 -PAY_AMT4,"(2716.36,3154.8]",1586,272,1314,0.052866666666666666,0.17150063051702397,-0.3163418373552002,0.004824786133896117,0.11576960255147234 -PAY_AMT4,"(3154.8,4000.0]",1524,314,1210,0.0508,0.20603674540682415,-0.09029541300600637,0.00040374737761363517,0.11576960255147234 -PAY_AMT4,"(4000.0,5024.0]",1848,273,1575,0.0616,0.14772727272727273,-0.4938514494166711,0.012974539782297524,0.11576960255147234 -PAY_AMT4,"(5024.0,7800.0]",2012,352,1660,0.06706666666666666,0.1749502982107356,-0.2922544780527202,0.005262177667191917,0.11576960255147234 -PAY_AMT4,"(7800.0,15161.050000000008]",2093,321,1772,0.06976666666666667,0.1533683707596751,-0.4497357490921214,0.012354534788869645,0.11576960255147234 -PAY_AMT4,"(15161.050000000008,+INF)",1583,189,1394,0.05276666666666667,0.11939355653821858,-0.7394981150465817,0.023060078515881488,0.11576960255147234 -PAY_AMT5,"(-INF,0.0]",6703,1970,4733,0.22343333333333334,0.2938982545129047,0.38216132530882274,0.036033601127500384,0.09668056235995909 -PAY_AMT5,"(0.0,390.0]",1671,362,1309,0.0557,0.21663674446439257,-0.02668735038539943,3.937505748169063e-05,0.09668056235995909 -PAY_AMT5,"(390.0,715.2]",1846,469,1377,0.061533333333333336,0.2540628385698808,0.18162741416544426,0.0021319953299833412,0.09668056235995909 -PAY_AMT5,"(715.2,1283.8000000000002]",3764,850,2914,0.12546666666666667,0.22582359192348567,0.02664144990903933,8.97131362403105e-05,0.09668056235995909 -PAY_AMT5,"(1283.8000000000002,1816.0]",1954,485,1469,0.06513333333333333,0.24820880245649948,0.1504988567254995,0.0015368491004839197,0.09668056235995909 -PAY_AMT5,"(1816.0,2000.0]",1663,373,1290,0.055433333333333334,0.2242934455802766,0.01786811671506457,1.7786311631959582e-05,0.09668056235995909 -PAY_AMT5,"(2000.0,2800.0]",1815,378,1437,0.0605,0.20826446280991737,-0.07673149164876286,0.00034857913474046923,0.09668056235995909 -PAY_AMT5,"(2800.0,3397.0]",1842,334,1508,0.0614,0.18132464712269272,-0.24871131865317841,0.0035347366707076523,0.09668056235995909 -PAY_AMT5,"(3397.0,4346.38]",1568,320,1248,0.05226666666666667,0.20408163265306123,-0.1022893169139866,0.0005312579671624588,0.09668056235995909 -PAY_AMT5,"(4346.38,5100.0]",1582,242,1340,0.05273333333333333,0.1529709228824273,-0.4527998243422136,0.009456919261511541,0.09668056235995909 -PAY_AMT5,"(5100.0,14281.240000000005]",3856,663,3193,0.12853333333333333,0.17193983402489627,-0.31325407916801234,0.011513230072411455,0.09668056235995909 -PAY_AMT5,"(14281.240000000005,+INF)",1736,190,1546,0.057866666666666663,0.10944700460829493,-0.8377146915044164,0.031446519190103904,0.09668056235995909 -PAY_AMT6,"(-INF,0.0]",7173,2078,5095,0.2391,0.2896974766485432,0.36183325834832153,0.03439945927691173,0.10313121089402558 -PAY_AMT6,"(0.0,480.0]",1998,457,1541,0.0666,0.22872872872872874,0.04318371334938594,0.00012569164412279887,0.10313121089402558 -PAY_AMT6,"(480.0,900.0]",2245,594,1651,0.07483333333333334,0.26458797327394207,0.2364299870731861,0.004456113008937193,0.10313121089402558 -PAY_AMT6,"(900.0,1078.0]",1967,404,1563,0.06556666666666666,0.20538891713268936,-0.09426026506526432,0.000567233057055399,0.10313121089402558 -PAY_AMT6,"(1078.0,1500.0]",1859,486,1373,0.06196666666666667,0.2614308768154922,0.2201423549104739,0.003185741252018165,0.10313121089402558 -PAY_AMT6,"(1500.0,2000.0]",2513,559,1954,0.08376666666666667,0.2224432948666932,0.007202772116025137,4.354534484569304e-06,0.10313121089402558 -PAY_AMT6,"(2000.0,2800.0]",1726,357,1369,0.05753333333333333,0.20683661645422943,-0.0854128325929556,0.00040972020074293494,0.10313121089402558 -PAY_AMT6,"(2800.0,3197.48]",1512,273,1239,0.0504,0.18055555555555555,-0.25390079700426565,0.003019147512670477,0.10313121089402558 -PAY_AMT6,"(3197.48,4000.0]",1524,317,1207,0.0508,0.20800524934383202,-0.07830421076306057,0.0003046756503547757,0.10313121089402558 -PAY_AMT6,"(4000.0,9927.44]",4544,745,3799,0.15146666666666667,0.1639524647887324,-0.3704218230527384,0.018644866028781033,0.10313121089402558 -PAY_AMT6,"(9927.44,+INF)",2939,366,2573,0.09796666666666666,0.12453215379380742,-0.6915072406716442,0.03801420872794651,0.10313121089402558 diff --git a/pyminer2/output/report_1588144520.html b/pyminer2/output/report_1588144520.html deleted file mode 100644 index ae3c3c17b54bc3826dbf91f0d6d9930564545adf..0000000000000000000000000000000000000000 --- a/pyminer2/output/report_1588144520.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - info - - - - - zheshiyizhangzhaopian - class.csv -
-

info

- -
- -

描述统计:Age

- - - - - - -
变量countmeanstdmin25%50%75%max
ID30,000.0015,000.508,660.401.007,500.7515,000.5022,500.2530,000.00
LIMIT_BAL30,000.00167,484.32129,747.6610,000.0050,000.00140,000.00240,000.001,000,000.00
SEX30,000.001.600.491.001.002.002.002.00
EDUCATION30,000.001.850.790.001.002.002.006.00
MARRIAGE30,000.001.550.520.001.002.002.003.00
AGE30,000.0035.499.2221.0028.0034.0041.0079.00
PAY_030,000.00-0.021.12-2.00-1.000.000.008.00
PAY_230,000.00-0.131.20-2.00-1.000.000.008.00
PAY_330,000.00-0.171.20-2.00-1.000.000.008.00
PAY_430,000.00-0.221.17-2.00-1.000.000.008.00
PAY_530,000.00-0.271.13-2.00-1.000.000.008.00
PAY_630,000.00-0.291.15-2.00-1.000.000.008.00
BILL_AMT130,000.0051,223.3373,635.86-165,580.003,558.7522,381.5067,091.00964,511.00
BILL_AMT230,000.0049,179.0871,173.77-69,777.002,984.7521,200.0064,006.25983,931.00
BILL_AMT330,000.0047,013.1569,349.39-157,264.002,666.2520,088.5060,164.751,664,089.00
BILL_AMT430,000.0043,262.9564,332.86-170,000.002,326.7519,052.0054,506.00891,586.00
BILL_AMT530,000.0040,311.4060,797.16-81,334.001,763.0018,104.5050,190.50927,171.00
BILL_AMT630,000.0038,871.7659,554.11-339,603.001,256.0017,071.0049,198.25961,664.00
PAY_AMT130,000.005,663.5816,563.280.001,000.002,100.005,006.00873,552.00
PAY_AMT230,000.005,921.1623,040.870.00833.002,009.005,000.001,684,259.00
PAY_AMT330,000.005,225.6817,606.960.00390.001,800.004,505.00896,040.00
PAY_AMT430,000.004,826.0815,666.160.00296.001,500.004,013.25621,000.00
PAY_AMT530,000.004,799.3915,278.310.00252.501,500.004,031.50426,529.00
PAY_AMT630,000.005,215.5017,777.470.00117.751,500.004,000.00528,666.00
target30,000.000.220.420.000.000.000.001.00
- - - diff --git a/pyminer2/output/report_1594010149.html b/pyminer2/output/report_1594010149.html deleted file mode 100644 index ae3c3c17b54bc3826dbf91f0d6d9930564545adf..0000000000000000000000000000000000000000 --- a/pyminer2/output/report_1594010149.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - info - - - - - zheshiyizhangzhaopian - class.csv -
-

info

- -
- -

描述统计:Age

- - - - - - -
变量countmeanstdmin25%50%75%max
ID30,000.0015,000.508,660.401.007,500.7515,000.5022,500.2530,000.00
LIMIT_BAL30,000.00167,484.32129,747.6610,000.0050,000.00140,000.00240,000.001,000,000.00
SEX30,000.001.600.491.001.002.002.002.00
EDUCATION30,000.001.850.790.001.002.002.006.00
MARRIAGE30,000.001.550.520.001.002.002.003.00
AGE30,000.0035.499.2221.0028.0034.0041.0079.00
PAY_030,000.00-0.021.12-2.00-1.000.000.008.00
PAY_230,000.00-0.131.20-2.00-1.000.000.008.00
PAY_330,000.00-0.171.20-2.00-1.000.000.008.00
PAY_430,000.00-0.221.17-2.00-1.000.000.008.00
PAY_530,000.00-0.271.13-2.00-1.000.000.008.00
PAY_630,000.00-0.291.15-2.00-1.000.000.008.00
BILL_AMT130,000.0051,223.3373,635.86-165,580.003,558.7522,381.5067,091.00964,511.00
BILL_AMT230,000.0049,179.0871,173.77-69,777.002,984.7521,200.0064,006.25983,931.00
BILL_AMT330,000.0047,013.1569,349.39-157,264.002,666.2520,088.5060,164.751,664,089.00
BILL_AMT430,000.0043,262.9564,332.86-170,000.002,326.7519,052.0054,506.00891,586.00
BILL_AMT530,000.0040,311.4060,797.16-81,334.001,763.0018,104.5050,190.50927,171.00
BILL_AMT630,000.0038,871.7659,554.11-339,603.001,256.0017,071.0049,198.25961,664.00
PAY_AMT130,000.005,663.5816,563.280.001,000.002,100.005,006.00873,552.00
PAY_AMT230,000.005,921.1623,040.870.00833.002,009.005,000.001,684,259.00
PAY_AMT330,000.005,225.6817,606.960.00390.001,800.004,505.00896,040.00
PAY_AMT430,000.004,826.0815,666.160.00296.001,500.004,013.25621,000.00
PAY_AMT530,000.004,799.3915,278.310.00252.501,500.004,031.50426,529.00
PAY_AMT630,000.005,215.5017,777.470.00117.751,500.004,000.00528,666.00
target30,000.000.220.420.000.000.000.001.00
- - - diff --git a/pyminer2/output/result.html b/pyminer2/output/result.html deleted file mode 100644 index 4e1f14fe0c21a1d6d03012fb6aae7294062670b2..0000000000000000000000000000000000000000 --- a/pyminer2/output/result.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - Document - - - - - -
NameSexAgeHeightWeight
0AlfredM1469.0112.5
1AliceF1356.584.0
2BarbaraF1365.398.0
3CarolF1462.8102.5
4HenryM1463.5102.5
5JamesM1257.383.0
6JaneF1259.884.5
7JanetF1562.5112.5
8JeffreyM1362.584.0
9JohnM1259.099.5
10JoyceF1151.350.5
11JudyF1464.390.0
12LouiseF1256.377.0
13MaryF1566.5112.0
14PhilipM1672.0150.0
15RobertM1264.8128.0
16RonaldM1567.0133.0
17ThomasM1157.585.0
18WilliamM1566.5112.0
- - - \ No newline at end of file diff --git a/pyminer2/output/role.csv b/pyminer2/output/role.csv deleted file mode 100644 index cdee5b7c368ef7dc085975209449e8b315f31e27..0000000000000000000000000000000000000000 --- a/pyminer2/output/role.csv +++ /dev/null @@ -1,6 +0,0 @@ -名称,类型,宽度,精度,标签,数量,缺失值,测量,角色 -Name,object,7,,,19,0,名义,输入 -Sex,object,1,,,19,0,名义,输入 -Age,int64,2,,,19,0,标度,输入 -Height,float64,4,1,,19,0,标度,输入 -Weight,float64,5,1,,19,0,标度,输入 diff --git a/pyminer2/output/tree_1.html b/pyminer2/output/tree_1.html deleted file mode 100644 index f52ebf239ca266f30288073670d3d9445d922ec9..0000000000000000000000000000000000000000 --- a/pyminer2/output/tree_1.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/pyminer2/output/tree_1.png b/pyminer2/output/tree_1.png deleted file mode 100644 index 2e4e797a4f6452a0dbe417b4ce38464275e76b54..0000000000000000000000000000000000000000 Binary files a/pyminer2/output/tree_1.png and /dev/null differ diff --git a/pyminer2/output/var_stats.csv b/pyminer2/output/var_stats.csv deleted file mode 100644 index a802efd5eb8587ddf5e51970785aaa8fe4ab15e6..0000000000000000000000000000000000000000 --- a/pyminer2/output/var_stats.csv +++ /dev/null @@ -1,6 +0,0 @@ -,变量名,数据类型,角色,水平,是否使用,总体计数,非缺失值计数,均值,均值标准误,方差,标准差,变异系数,总和,平方和,众数,最小值,Q1,中位数,Q3,最大值,极差,四分位间距,峰度,偏度,缺失值,缺失值占比,唯一值,唯一值占比 -0,Name,object,输入,名义型,是,19,19,,,,,,,,Alfred,,,,,,,,,,0,0.00%,19,100.00% -1,Sex,object,输入,二值型,是,19,19,,,,,,,,M,,,,,,,,,,0,0.00%,2,10.53% -2,Age,int64,输入,区间型,是,19,19,13.3158,0.5112,2.2281,1.4927,0.1121,253.0000,"3,409.0000",12,11,12.0000,13.0000,14.5000,16,5.0000,2.5000,-1.1109,0.0636,0,0.00%,6,31.58% -3,Height,float64,输入,区间型,是,19,19,62.3368,6.0306,26.2869,5.1271,0.0822,"1,184.4000","74,304.9200",62.5,51.3,58.2500,62.8000,65.9000,72.0,20.7000,7.6500,-0.1390,-0.2597,0,0.00%,17,89.47% -4,Weight,float64,输入,区间型,是,19,19,100.0263,118.9869,518.6520,22.7739,0.2277,"1,900.5000","199,435.7500",84.0,50.5,84.2500,99.5000,112.2500,150.0,99.5000,28.0000,0.6834,0.1834,0,0.00%,15,78.95% diff --git a/pyminer2/test/data/TitanicData.xlsx b/pyminer2/test/data/TitanicData.xlsx deleted file mode 100644 index d3709179db735dbaafbc4a32dc34bec77e218595..0000000000000000000000000000000000000000 Binary files a/pyminer2/test/data/TitanicData.xlsx and /dev/null differ diff --git a/pyminer2/test/data/class.csv b/pyminer2/test/data/class.csv deleted file mode 100644 index ad1ffc74622ef52c95ac7a296023bc88e8735d8e..0000000000000000000000000000000000000000 --- a/pyminer2/test/data/class.csv +++ /dev/null @@ -1,20 +0,0 @@ -Name,Sex,Age,Height,Weight -Alfred,M,14,69,112.5 -Alice,F,13,56.5,84 -Barbara,F,13,65.3,98 -Carol,F,14,62.8,102.5 -Henry,M,14,63.5,102.5 -James,M,12,57.3,83 -Jane,F,12,59.8,84.5 -Janet,F,15,62.5,112.5 -Jeffrey,M,13,62.5,84 -John,M,12,59,99.5 -Joyce,F,11,51.3,50.5 -Judy,F,14,64.3,90 -Louise,F,12,56.3,77 -Mary,F,15,66.5,112 -Philip,M,16,72,150 -Robert,M,12,64.8,128 -Ronald,M,15,67,133 -Thomas,M,11,57.5,85 -William,M,15,66.5,112 diff --git a/pyminer2/tests/__init__.py b/pyminer2/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..33c9e0acb14962849921ddde86f0c44d23c449e7 --- /dev/null +++ b/pyminer2/tests/__init__.py @@ -0,0 +1,106 @@ +import os +import unittest +import tempfile +from contextlib import contextmanager + +try: + from numpy.testing import assert_array_compare +except ImportError: + # numpy < 1.14 + from numpy.testing.utils import assert_array_compare + +import numpy as np +import Orange + + +@contextmanager +def named_file(content, encoding=None, suffix=''): + file = tempfile.NamedTemporaryFile("wt", delete=False, + encoding=encoding, suffix=suffix) + file.write(content) + name = file.name + file.close() + try: + yield name + finally: + os.remove(name) + + +@np.vectorize +def naneq(a, b): + try: + return (np.isnan(a) and np.isnan(b)) or a == b + except TypeError: + return a == b + + +def assert_array_nanequal(a, b, *args, **kwargs): + """ + Similar as np.testing.assert_array_equal but with better handling of + object arrays. + + Note + ---- + Is not fast! + + Parameters + ---------- + a : array-like + b : array-like + """ + return assert_array_compare(naneq, a, b, *args, **kwargs) + + +def test_dirname(): + """ + Return the absolute path to the Orange.tests package. + + Returns + ------- + path : str + """ + return os.path.dirname(__file__) + + +def test_filename(path): + """ + Return an absolute path to a resource within Orange.tests package. + + Parameters + ---------- + path : str + Path relative to `test_dirname()` + Returns + ------- + abspath : str + Absolute path + """ + return os.path.join(test_dirname(), path) + + +def suite(loader=None, pattern='test*.py'): + test_dir = os.path.dirname(__file__) + if loader is None: + loader = unittest.TestLoader() + if pattern is None: + pattern = 'test*.py' + orange_dir = os.path.dirname(Orange.__file__) + top_level_dir = os.path.dirname(orange_dir) + all_tests = [loader.discover(test_dir, pattern, top_level_dir)] + if not suite.in_tests: # prevent recursion + suite.in_tests = True + all_tests += (loader.discover(dir, pattern, dir) + for dir in (os.path.join(orange_dir, fn, "tests") + for fn in os.listdir(orange_dir) + if fn != "widgets") + if os.path.exists(dir)) + return unittest.TestSuite(all_tests) + +suite.in_tests = False + +def load_tests(loader, tests, pattern): + return suite(loader, pattern) + + +if __name__ == '__main__': + unittest.main(defaultTest='suite') diff --git a/pyminer2/tests/base.py b/pyminer2/tests/base.py new file mode 100644 index 0000000000000000000000000000000000000000..7c7baedbe95762a4f7098d3c2621e23c895ed6c9 --- /dev/null +++ b/pyminer2/tests/base.py @@ -0,0 +1,57 @@ +import pickle +from unittest import TestCase + +from Orange.data import Variable, Domain + + +class PickleTest(TestCase): + def setUp(self): + """ Override __eq__ for Orange objects that do not implement it""" + self.add_comparator(Domain, + compare_members=("attributes", "class_vars", + "class_var", "variables", + "metas", "anonymous")) + + old_comparators = {} + + def add_comparator(self, class_, compare_members): + def compare(self, y): + for m in compare_members: + if getattr(self, m) != getattr(y, m): + return False + return True + + def hash(self): + return "".join( + [str(getattr(self, m)) for m in compare_members]).__hash__() + + self.old_comparators[class_] = (class_.__eq__, class_.__hash__) + class_.__eq__ = compare + class_.__hash__ = hash + + def tearDown(self): + for c, (eq, hash) in self.old_comparators.items(): + c.__eq__, c.__hash__ = eq, hash + + def assertPicklingPreserves(self, obj): + for protocol in range(1, pickle.HIGHEST_PROTOCOL + 1): + obj2 = pickle.loads(pickle.dumps(obj, protocol)) + self.assertEqual(obj, obj2) + + +def create_pickling_tests(classname, *objs): + def create_test(descr): + name, construct_object = descr + name = "test_{}".format(name) + + def f(self): + obj = construct_object() + self.assertPicklingPreserves(obj) + + f.__name__ = name + return name, f + + tests = dict(map(create_test, objs)) + return type(classname, (PickleTest,), tests) + +create_pickling_tests.__test__ = False # Tell nose this is not a test. diff --git a/pyminer2/tests/datasets/adult_sample_missing.tab b/pyminer2/tests/datasets/adult_sample_missing.tab new file mode 100644 index 0000000000000000000000000000000000000000..47ca628f889e861fec4a93fac2bec9d7bdd421dc --- /dev/null +++ b/pyminer2/tests/datasets/adult_sample_missing.tab @@ -0,0 +1,23 @@ +age workclass fnlwgt education education-num marital-status occupation relationship race sex capital-gain capital-loss hours-per-week native-country y +continuous Private Self-emp-not-inc Self-emp-inc Federal-gov Local-gov State-gov Without-pay Never-worked continuous Bachelors Some-college 11th HS-grad Prof-school Assoc-acdm Assoc-voc 9th 7th-8th 12th Masters 1st-4th 10th Doctorate 5th-6th Preschool continuous Married-civ-spouse Divorced Never-married Separated Widowed Married-spouse-absent Married-AF-spouse Tech-support Craft-repair Other-service Sales Exec-managerial Prof-specialty Handlers-cleaners Machine-op-inspct Adm-clerical Farming-fishing Transport-moving Priv-house-serv Protective-serv Armed-Forces Wife Own-child Husband Not-in-family Other-relative Unmarried White Asian-Pac-Islander Amer-Indian-Eskimo Other Black Female Male continuous continuous continuous United-States Cuba Jamaica India Mexico South Puerto-Rico Honduras England Canada Germany Iran Philippines Italy Poland Columbia Cambodia Thailand Ecuador Laos Taiwan Haiti Portugal Dominican-Republic El-Salvador France Guatemala China Japan Yugoslavia Peru Outlying-US(Guam-USVI-etc) Scotland Trinadad&Tobago Greece Nicaragua Vietnam Hong Ireland Hungary Holand-Netherlands >50K <=50K + class +49 Private 193366 HS-grad 9 Married-civ-spouse Craft-repair Husband White Male 0 0 40 United-States <=50K +44 Private 128354 Masters 14 Divorced Exec-managerial Unmarried White Female 0 0 40 United-States <=50K +29 Private 105598 Some-college 10 Divorced Tech-support Not-in-family White Male 0 0 58 United-States <=50K +76 Private 124191 Masters 14 Married-civ-spouse Exec-managerial Husband White Male 0 0 40 United-States >50K +59 Private 146013 Some-college 10 Married-civ-spouse Sales Husband White Male 4064 0 40 United-States +17 Private 191260 9th 5 Never-married Other-service Own-child White Male 1055 0 24 United-States <=50K +65 Private 111095 HS-grad 9 Married-civ-spouse Transport-moving Husband White Male 0 0 16 United-States <=50K +24 Private 303296 Some-college 10 Married-civ-spouse Adm-clerical Wife Asian-Pac-Islander Female 0 0 40 Laos <=50K +23 211601 Assoc-voc 11 Never-married Own-child Black Female 0 0 15 United-States +43 Private 187728 Some-college 10 Married-civ-spouse Prof-specialty Wife White Female 0 1887 50 United-States >50K +22 State-gov 293364 Some-college 10 Never-married Protective-serv Own-child Black Female 0 0 40 United-States <=50K +34 State-gov 98101 Bachelors 13 Married-civ-spouse Exec-managerial Husband White Male 7688 0 45 >50K +46 Private 188386 Doctorate 16 Married-civ-spouse Exec-managerial Husband White Male 15024 0 60 United-States >50K +38 Private 91039 Bachelors Married-civ-spouse Sales Husband White Male 15024 0 60 United-States +74 Private 99183 Some-college 10 Divorced Adm-clerical Not-in-family White Female 0 0 9 United-States <=50K +45 Private 433665 7th-8th 4 Separated Other-service Unmarried White Female 0 0 40 Mexico <=50K +29 Private 34292 Some-college 10 Adm-clerical Not-in-family White Male 0 0 60 United-States +18 Private 156764 11th Never-married Other-service Own-child White Male 0 0 40 United-States <=50K +24 Private 247564 HS-grad 9 Never-married Craft-repair Not-in-family White Male 0 0 40 United-States <=50K +47 Private 241832 9th 5 Married-spouse-absent Handlers-cleaners Unmarried White Male 0 0 40 El-Salvador <=50K \ No newline at end of file diff --git a/pyminer2/tests/datasets/binary-blob.tab b/pyminer2/tests/datasets/binary-blob.tab new file mode 100644 index 0000000000000000000000000000000000000000..baf0c725e68c37264d60d63588e7dd0a818b8f0a Binary files /dev/null and b/pyminer2/tests/datasets/binary-blob.tab differ diff --git a/pyminer2/tests/datasets/breast-cancer-wisconsin.tab b/pyminer2/tests/datasets/breast-cancer-wisconsin.tab new file mode 100644 index 0000000000000000000000000000000000000000..d8c4548b0a8dd41675cdb897fbc22ba74572ab35 --- /dev/null +++ b/pyminer2/tests/datasets/breast-cancer-wisconsin.tab @@ -0,0 +1,686 @@ +Clump thickness Unif_Cell_Size Unif_Cell_Shape Marginal_Adhesion Single_Cell_Size Bare_Nuclei Bland_Chromatine Normal_Nucleoli Mitoses type +continuous continuous continuous continuous continuous continuous continuous continuous continuous benign malign + class +4.05 0.05 0.48 0.13 1.46 0.79 2.14 0.83 0.93 benign +4.86 3.90 3.14 4.73 6.04 9.62 2.25 1.34 0.81 benign +2.48 0.09 0.11 0.40 1.94 1.98 2.56 0.87 0.73 benign +5.33 7.14 7.96 0.29 2.12 3.10 2.78 6.68 0.79 benign +3.13 0.09 0.74 2.49 1.51 0.61 2.43 0.80 0.36 benign +7.34 9.81 9.85 7.29 6.37 9.07 8.38 6.46 0.32 malign +0.41 0.27 0.94 0.10 1.84 9.55 2.35 0.88 0.47 benign +1.44 0.64 1.47 0.42 1.40 0.29 2.61 0.87 0.87 benign +1.38 0.04 0.56 0.17 1.26 0.82 0.76 1.00 4.67 benign +3.15 1.17 0.16 0.88 1.56 0.69 1.59 0.78 0.54 benign +0.19 0.56 0.47 0.74 0.63 0.04 2.77 0.43 0.55 benign +1.11 0.02 0.88 0.09 1.68 0.31 1.33 0.68 0.65 benign +4.16 2.74 2.96 2.93 1.35 2.83 3.82 3.60 0.68 malign +0.09 0.33 0.46 0.11 1.35 2.75 2.17 0.84 0.31 benign +7.30 6.99 4.95 9.35 6.06 8.73 4.56 4.83 3.04 malign +6.96 3.76 5.22 3.18 5.60 0.04 3.92 2.80 0.75 malign +3.74 0.25 0.55 0.42 1.33 0.14 1.39 0.51 0.76 benign +3.37 0.62 0.66 0.56 1.11 0.49 2.64 0.80 0.17 benign +9.64 6.90 6.08 5.22 3.62 9.08 3.25 0.98 1.94 malign +5.23 0.69 0.57 0.47 1.06 0.90 2.87 0.10 0.45 benign +6.03 2.47 1.64 9.15 4.48 9.86 4.43 3.58 3.73 malign +9.18 4.07 4.49 2.83 5.19 6.42 6.16 9.94 0.15 malign +2.21 0.53 0.61 0.41 1.17 0.83 1.77 0.54 0.30 benign +0.37 0.69 0.35 0.74 1.01 0.09 2.86 0.95 0.22 benign +4.29 1.95 2.16 3.34 1.75 6.34 2.98 5.22 0.24 malign +2.15 1.78 0.88 0.19 0.09 0.55 1.47 0.70 0.12 benign +4.06 0.52 0.20 0.93 1.54 0.07 1.99 0.10 0.41 benign +1.68 0.44 0.41 0.57 1.62 0.35 1.38 0.92 0.11 benign +0.00 0.63 2.93 0.11 1.88 0.88 0.53 0.18 0.94 benign +2.66 0.93 1.00 0.66 0.83 0.39 1.93 0.10 0.78 benign +1.52 0.50 0.25 0.23 1.58 0.98 2.49 0.49 0.09 benign +9.34 6.05 6.54 2.02 7.06 4.78 6.16 3.58 2.53 malign +1.49 0.91 0.97 1.46 1.91 0.92 2.03 0.15 0.02 benign +2.78 0.55 1.30 0.61 1.83 0.88 1.69 0.92 0.35 benign +1.28 0.17 0.17 0.26 1.90 0.53 1.74 0.03 0.61 benign +9.67 9.95 9.97 7.14 5.18 0.38 7.97 8.08 0.33 malign +5.67 1.79 0.45 0.64 0.79 0.58 6.04 0.35 0.59 benign +4.61 3.53 3.89 8.69 1.22 9.81 4.10 5.88 0.45 malign +1.40 4.19 2.37 2.11 5.27 6.64 6.75 4.33 0.62 malign +9.97 3.37 2.44 0.03 2.77 2.19 5.89 5.00 1.42 malign +5.44 9.31 9.42 1.45 7.27 9.61 6.74 2.73 2.06 malign +4.88 5.60 4.20 5.01 9.88 0.78 2.62 0.27 0.81 malign +9.59 9.79 9.79 3.55 7.73 0.45 7.05 9.06 0.95 malign +0.93 0.59 0.00 0.13 1.73 0.31 1.43 0.54 1.19 benign +2.74 6.46 6.90 3.35 3.68 8.90 4.00 7.66 0.71 malign +0.29 0.06 0.57 0.99 1.07 0.96 1.22 0.30 0.83 benign +3.29 0.58 0.04 2.03 1.80 0.23 2.89 0.18 0.19 benign +6.61 7.18 6.12 1.57 3.68 7.71 2.66 7.26 1.98 malign +8.53 4.21 7.36 0.32 1.24 2.33 1.59 0.05 4.94 malign +4.45 2.50 2.49 3.60 1.68 3.32 2.91 3.55 0.89 malign +9.68 2.67 5.46 1.36 2.14 4.12 3.80 9.76 1.52 malign +4.46 4.89 4.07 7.32 9.84 7.69 6.13 2.06 6.52 malign +9.75 4.12 4.35 5.99 7.19 7.41 6.43 0.28 0.12 malign +9.48 5.27 5.01 2.96 3.84 4.25 2.92 5.76 0.54 malign +7.65 9.24 9.48 0.19 2.66 5.71 2.96 8.40 0.53 malign +7.29 1.11 3.42 0.07 4.63 0.25 4.17 3.76 3.11 malign +4.66 1.91 2.22 0.28 5.07 9.36 4.67 0.76 0.90 malign +8.59 4.00 4.37 1.85 1.02 1.11 4.36 0.17 0.21 malign +4.64 2.59 4.29 4.05 2.67 2.69 3.02 9.56 0.83 malign +0.41 0.07 0.87 0.37 1.51 1.40 1.92 0.43 0.86 benign +8.34 9.18 10.00 0.77 9.20 7.72 2.99 2.85 0.51 malign +5.93 2.82 3.82 0.67 4.48 1.46 2.32 8.54 0.46 malign +1.00 0.26 0.69 0.60 1.18 0.91 1.18 0.81 0.85 benign +9.17 3.95 1.80 0.09 2.95 1.16 3.49 2.36 9.13 malign +3.43 0.28 0.20 0.08 1.12 0.48 2.28 0.92 0.65 benign +4.12 2.07 3.70 0.43 7.22 9.28 3.68 8.65 0.53 malign +7.80 2.45 7.79 2.44 3.53 8.57 7.46 8.10 7.65 malign +0.02 0.53 0.31 0.19 1.34 0.66 2.81 1.81 0.44 benign +4.83 0.48 2.88 0.40 1.88 0.81 1.52 0.29 0.36 benign +5.58 9.94 1.20 8.00 9.13 1.14 6.94 7.63 9.92 malign +0.61 2.38 2.28 1.85 1.29 0.54 6.25 1.42 0.95 benign +8.32 3.68 4.37 9.78 5.88 9.72 3.57 7.51 0.31 malign +9.94 5.64 3.17 0.06 2.89 3.52 2.28 1.03 2.55 malign +0.65 0.52 1.11 0.01 1.75 1.84 3.87 1.95 1.00 benign +0.18 0.74 3.91 0.40 1.57 0.61 1.96 0.54 0.01 benign +4.22 2.11 0.27 1.20 2.00 0.01 1.02 0.69 0.81 benign +2.72 0.39 0.38 0.41 1.77 2.16 2.16 0.51 0.91 benign +1.81 0.37 0.92 0.81 2.23 0.00 1.26 0.80 0.08 benign +1.97 1.01 1.76 0.01 0.33 0.40 6.04 0.84 0.51 benign +3.73 0.48 0.99 1.11 1.41 0.73 1.09 0.81 0.93 benign +4.19 1.57 0.99 0.25 1.36 0.29 2.01 0.16 0.28 benign +2.69 0.34 0.07 0.92 1.25 1.42 6.29 0.98 0.45 benign +2.83 4.96 6.01 7.04 7.10 8.90 6.81 9.03 6.98 malign +4.46 9.03 5.44 0.50 9.11 3.29 3.96 9.12 9.88 malign +2.76 2.44 5.12 3.48 4.55 7.73 3.41 3.75 0.19 malign +2.24 5.85 5.32 5.56 4.99 9.69 5.92 7.65 2.85 malign +3.39 0.17 0.93 0.88 1.57 0.65 2.65 0.02 0.02 benign +1.53 0.41 0.66 1.17 2.61 0.87 1.66 0.50 0.92 benign +0.23 0.64 0.25 0.89 1.50 0.77 2.75 0.06 0.67 benign +2.31 0.09 0.59 1.31 1.89 0.85 0.14 0.96 0.43 benign +3.08 0.54 0.81 0.31 1.39 0.15 2.59 0.13 0.79 benign +0.91 0.94 0.55 0.36 1.07 0.12 1.04 0.91 0.17 benign +2.00 0.57 0.58 0.19 1.75 0.17 2.62 0.32 0.54 benign +0.91 0.05 0.78 0.23 1.90 0.92 2.06 0.33 0.52 benign +1.41 0.99 0.86 1.32 1.30 0.57 0.23 0.86 0.81 benign +5.00 0.02 0.11 0.16 1.80 0.39 2.41 0.08 0.96 benign +8.50 5.89 8.45 1.06 9.19 5.59 1.14 8.55 9.61 malign +6.14 4.10 5.33 9.73 4.90 9.25 6.64 8.96 3.53 malign +9.51 2.96 4.39 0.98 9.80 4.81 2.33 9.12 1.21 malign +1.67 2.61 3.11 3.27 1.53 4.30 1.83 4.47 0.85 malign +3.16 0.11 1.54 0.61 1.64 0.58 2.12 0.45 0.62 benign +7.97 1.99 2.02 0.93 5.82 2.09 6.49 0.98 0.55 malign +9.38 9.53 9.88 9.33 9.82 0.78 7.79 7.68 7.49 malign +6.03 2.34 3.10 3.80 2.69 2.90 2.50 1.54 6.74 malign +9.69 9.24 9.53 7.51 1.15 9.43 3.22 0.78 0.04 malign +0.97 5.34 7.99 9.44 7.87 9.53 4.08 6.25 0.35 malign +0.83 0.50 0.13 0.71 1.51 0.76 1.86 2.08 0.12 benign +5.06 4.00 3.95 3.71 2.54 8.72 6.21 7.29 2.72 malign +0.60 2.89 0.84 1.45 1.51 1.74 4.90 2.67 1.50 benign +7.06 5.31 3.38 2.67 4.73 8.91 2.42 0.42 0.54 malign +9.47 2.07 2.70 9.38 1.32 9.97 6.72 2.18 2.63 malign +9.67 9.96 9.27 2.40 9.49 7.93 7.90 0.33 0.06 malign +2.34 2.58 1.00 0.49 1.17 2.34 2.88 0.32 0.83 benign +0.69 0.88 0.47 0.42 1.51 4.08 0.74 0.02 0.09 benign +7.27 2.73 2.31 0.84 1.18 2.00 2.42 1.26 0.67 benign +3.26 4.50 4.20 9.85 3.34 9.75 6.19 4.33 7.85 malign +0.45 0.48 0.43 0.98 3.46 2.48 0.10 0.25 0.24 benign +2.81 1.56 0.98 0.71 1.78 1.29 2.52 0.81 0.15 benign +0.01 0.13 1.29 1.39 1.83 0.05 2.55 0.01 0.85 benign +3.50 1.09 0.43 0.46 1.30 1.86 2.91 0.88 0.37 benign +9.59 9.51 9.00 1.33 9.66 9.58 4.29 2.72 2.35 malign +4.85 2.98 4.44 0.06 7.32 9.74 4.46 2.43 0.87 malign +4.12 3.14 5.24 6.37 8.12 6.56 7.59 9.47 0.17 malign +0.73 0.82 0.79 0.76 1.68 0.72 1.36 0.33 0.10 benign +6.08 4.00 2.86 6.62 3.87 9.59 6.52 4.11 4.89 malign +2.32 0.26 0.51 0.44 1.08 0.96 2.97 0.47 0.21 benign +7.05 2.77 4.88 3.13 4.98 9.00 0.11 5.94 1.87 malign +0.99 0.67 0.45 0.73 9.04 0.63 0.45 0.69 0.06 benign +4.74 0.19 2.33 0.97 1.57 0.39 1.05 0.06 0.31 benign +1.97 0.62 0.31 0.27 1.40 0.61 2.67 0.33 0.21 benign +4.66 9.40 7.81 9.57 7.72 9.38 2.05 5.52 2.99 malign +2.64 0.92 0.97 0.06 1.60 0.15 1.02 1.93 0.28 benign +2.77 0.05 0.31 0.27 2.91 0.36 1.59 0.38 0.67 benign +4.09 0.31 0.83 0.98 1.43 1.67 2.52 2.29 0.56 benign +3.97 0.52 0.76 0.05 1.66 0.08 1.92 0.05 0.84 benign +2.49 0.11 0.63 0.76 1.87 0.36 0.80 0.25 0.96 benign +3.35 0.89 1.80 0.35 1.86 0.97 1.48 0.74 0.45 benign +2.40 0.08 0.16 0.88 1.09 0.43 0.63 0.51 0.57 benign +1.55 0.15 0.31 0.07 1.97 0.42 0.74 0.54 0.55 benign +9.00 4.59 4.05 3.94 3.88 4.07 3.95 3.00 2.98 malign +0.99 0.01 0.72 0.64 1.59 4.83 0.60 0.19 0.29 benign +1.85 0.38 0.96 0.13 1.28 0.15 1.64 0.62 0.42 benign +2.76 3.48 4.16 1.82 5.04 7.63 3.81 0.26 0.93 malign +0.49 0.29 0.85 0.36 2.01 1.75 1.63 0.98 0.65 benign +2.58 0.50 0.95 2.76 7.42 0.58 4.23 7.05 0.44 benign +7.41 7.09 6.59 3.55 9.56 9.88 6.42 7.53 6.74 malign +0.83 0.17 0.68 0.22 0.73 0.93 2.36 0.78 0.82 benign +6.15 1.71 3.97 0.61 5.55 9.17 4.78 3.01 2.82 malign +9.79 9.81 7.04 5.57 3.69 4.15 7.33 9.95 0.77 malign +3.84 0.17 0.66 0.49 1.55 2.98 0.59 0.28 0.20 benign +0.77 0.18 0.64 0.82 1.93 0.35 0.76 0.08 0.87 benign +5.00 4.92 4.65 5.29 2.63 9.22 2.81 0.78 0.13 malign +0.89 1.02 1.39 0.88 1.56 0.23 1.22 0.16 0.83 benign +1.99 0.65 0.94 0.19 1.63 0.54 2.46 0.94 0.85 benign +8.75 8.06 9.71 2.92 5.61 9.28 6.83 9.47 5.62 malign +9.70 6.33 6.17 3.18 4.14 9.81 4.43 6.68 1.92 malign +3.58 0.86 0.15 0.85 1.10 0.55 2.36 1.89 0.33 benign +2.24 0.52 0.06 0.66 1.23 0.58 2.97 0.53 0.26 benign +0.94 0.75 0.89 1.30 0.47 2.20 0.01 0.18 6.03 benign +3.44 0.54 0.65 0.93 1.62 1.06 2.93 1.90 0.26 benign +4.64 5.36 6.91 7.43 7.41 9.67 2.74 9.71 2.31 malign +9.34 7.89 9.79 9.15 5.52 0.24 2.42 0.75 9.91 malign +2.82 0.35 0.42 0.05 1.38 0.06 2.01 0.23 0.01 benign +0.16 0.84 0.38 1.75 0.02 0.27 0.77 0.29 0.61 benign +2.68 0.95 0.46 0.40 1.88 0.90 0.62 0.98 0.92 benign +0.87 0.66 0.83 0.57 1.34 0.75 2.65 0.08 0.28 benign +0.17 0.13 0.45 0.24 1.44 0.54 1.21 0.61 0.84 benign +5.80 9.67 9.81 9.14 7.08 9.22 9.97 9.83 6.06 malign +7.92 5.34 4.61 3.43 2.81 9.25 5.75 0.51 0.60 malign +4.45 7.71 6.32 6.92 9.66 9.49 4.36 6.21 0.10 malign +1.12 0.28 0.74 0.76 1.52 0.87 2.60 0.41 0.70 benign +4.50 9.09 9.74 2.22 7.91 0.13 4.21 9.03 2.02 malign +3.22 0.73 0.41 0.97 1.23 0.20 2.99 0.40 0.47 benign +4.45 2.65 2.14 2.37 5.96 9.15 2.68 0.50 0.32 malign +0.78 0.52 0.72 0.39 0.77 0.10 2.20 0.54 0.17 benign +0.76 0.05 0.43 0.85 1.58 0.40 0.39 0.00 0.62 benign +5.34 0.67 0.04 0.07 1.50 0.38 2.52 0.41 0.31 benign +4.50 7.89 7.37 7.40 4.94 9.59 6.09 7.01 0.27 malign +7.68 6.82 5.76 3.85 3.33 9.21 4.87 0.96 0.04 malign +1.68 0.14 0.17 0.93 0.12 0.48 2.61 0.41 0.52 benign +0.31 4.68 7.29 5.24 4.07 7.57 6.33 9.64 0.91 malign +9.06 4.10 5.99 9.42 5.26 9.42 6.28 6.98 9.41 malign +4.71 7.39 3.81 9.88 4.67 7.12 8.81 10.00 0.71 malign +0.30 1.52 2.10 0.03 1.87 0.72 2.91 0.65 0.52 benign +9.55 9.14 9.64 7.46 5.40 7.22 6.42 9.83 0.42 malign +6.08 4.91 9.90 9.48 9.48 9.16 3.83 9.20 2.59 malign +4.01 0.57 0.73 0.23 1.70 0.04 1.00 0.33 0.36 benign +0.20 0.76 0.09 0.11 1.75 0.63 2.57 0.34 0.13 benign +2.71 0.02 1.00 0.60 1.23 0.98 2.35 0.13 0.43 benign +3.17 0.09 0.31 0.87 1.53 0.34 2.45 0.75 0.14 benign +7.69 3.74 3.34 4.79 3.80 6.87 6.06 7.11 1.61 benign +4.20 0.90 0.85 3.75 1.74 0.31 2.21 0.39 0.03 benign +0.27 0.12 0.23 0.36 1.07 0.40 0.75 0.49 0.15 benign +2.97 0.65 0.27 0.05 1.55 0.35 1.21 0.07 0.69 benign +8.49 6.76 6.87 4.81 4.59 9.88 6.79 7.93 2.19 malign +9.80 7.94 7.66 3.91 9.04 9.20 7.25 0.13 0.16 malign +0.71 0.38 0.46 0.68 2.00 0.35 2.62 0.26 0.61 benign +4.23 0.06 0.30 0.95 1.40 0.62 2.13 0.53 0.03 benign +0.04 0.23 0.02 0.41 1.12 0.29 2.08 0.67 0.58 benign +4.81 9.59 9.17 8.65 5.36 9.59 6.69 9.48 4.19 malign +9.38 9.42 8.05 2.75 6.41 4.97 2.51 4.13 0.43 malign +0.65 0.05 0.13 0.98 0.22 0.96 2.32 0.68 0.50 benign +0.64 0.82 0.65 0.85 0.49 0.31 2.61 0.99 0.56 benign +4.94 0.83 0.79 0.80 0.02 0.23 2.64 0.24 0.14 benign +7.32 9.25 9.36 9.46 4.98 9.67 7.54 9.25 5.48 malign +7.58 9.45 7.57 7.76 3.53 7.75 6.34 6.57 0.86 malign +0.60 0.18 0.55 0.41 1.27 0.23 2.02 0.80 0.53 benign +9.11 9.91 9.52 9.55 6.61 9.39 6.21 9.79 3.77 malign +9.80 9.92 9.48 9.96 2.39 9.63 9.19 5.46 0.58 malign +7.40 6.37 7.10 6.76 4.47 4.79 4.68 9.23 1.03 malign +0.81 0.36 0.62 0.11 1.40 0.06 1.31 0.06 0.25 benign +0.96 0.51 0.34 0.32 1.77 0.16 2.86 0.82 0.31 benign +5.31 9.19 6.46 6.21 5.29 3.17 7.21 9.59 1.92 malign +5.50 0.90 2.69 0.26 1.84 0.43 2.69 0.01 0.84 benign +0.70 0.35 0.17 1.06 1.47 0.74 2.44 0.31 0.82 benign +9.83 5.88 3.60 2.67 9.65 9.68 8.99 9.58 0.34 malign +3.89 0.27 0.17 2.01 0.94 4.22 1.65 0.49 0.73 malign +6.94 4.34 5.67 2.18 2.58 7.54 6.25 3.05 0.56 malign +9.18 4.19 4.14 5.83 2.90 9.91 6.28 8.63 1.26 malign +0.43 0.12 0.18 0.38 1.14 0.62 1.93 0.87 0.89 benign +9.77 4.22 6.47 3.01 3.99 9.79 7.47 8.31 0.23 malign +7.61 8.62 8.61 4.51 2.36 4.32 6.54 6.30 0.93 malign +0.27 0.87 0.74 0.82 0.34 0.86 2.63 0.83 0.33 benign +9.10 9.09 9.55 2.77 9.20 9.92 8.02 9.13 0.53 malign +6.45 3.91 6.36 3.35 2.75 6.09 6.31 5.15 0.49 malign +5.01 7.53 6.37 4.80 5.54 7.55 7.07 8.25 1.85 malign +7.16 3.37 5.42 2.36 2.58 0.27 3.34 2.05 0.62 benign +9.43 3.80 4.73 4.87 4.87 9.96 3.53 0.53 0.68 malign +2.54 2.54 1.56 0.21 2.29 0.58 2.37 5.49 0.42 benign +9.61 7.13 7.40 1.76 7.06 9.00 3.84 7.95 9.87 malign +8.47 7.09 7.28 4.87 5.98 1.44 3.42 9.57 3.23 malign +7.59 9.23 9.57 7.39 5.23 8.63 2.47 9.66 9.39 malign +9.49 3.47 2.78 1.93 2.35 9.47 4.53 2.27 1.35 malign +4.16 0.16 2.04 2.90 1.22 1.83 1.56 2.59 0.33 benign +2.05 0.99 0.49 2.53 0.12 0.86 2.04 0.86 0.23 benign +1.65 0.38 0.36 0.36 1.23 0.84 2.36 0.18 0.44 benign +0.18 0.53 0.41 0.77 1.87 4.21 4.28 0.92 0.69 benign +0.96 0.89 0.90 0.25 1.53 0.65 2.83 0.10 0.70 benign +4.08 0.68 0.07 1.89 1.79 1.85 2.06 0.51 0.75 benign +7.76 9.76 9.34 7.43 4.31 9.44 6.26 7.66 0.03 malign +7.92 3.50 3.92 0.64 1.73 8.96 2.24 2.52 0.58 malign +3.95 0.71 0.38 0.51 1.97 0.76 2.70 5.35 0.90 benign +0.50 1.81 1.09 0.87 1.74 0.20 0.43 0.58 0.42 benign +9.10 3.38 3.55 9.74 1.56 9.41 4.23 2.95 2.17 malign +5.80 2.51 2.93 4.77 2.29 9.81 2.58 4.72 2.62 benign +5.66 9.47 9.36 1.06 7.72 9.52 6.48 2.90 2.79 malign +8.54 9.40 9.19 0.65 9.84 7.68 2.15 2.06 0.91 malign +4.97 5.15 5.17 1.32 3.33 9.81 2.09 5.75 0.45 malign +2.77 0.17 0.13 0.32 1.94 0.64 0.48 0.59 0.46 benign +2.87 0.57 0.17 0.25 1.24 0.33 1.90 0.26 0.20 benign +2.40 0.53 0.37 0.92 1.11 0.39 2.83 0.06 0.89 benign +4.60 6.18 6.76 0.63 4.81 7.96 2.70 3.72 0.90 benign +9.82 4.46 7.50 9.47 2.07 9.31 4.10 0.90 2.58 malign +4.59 9.84 9.17 5.89 9.48 9.88 9.44 5.21 4.04 malign +7.75 7.60 8.65 3.09 4.59 9.51 7.00 7.24 0.07 malign +9.59 3.53 3.77 9.75 5.49 9.95 4.23 4.30 0.15 malign +6.84 8.83 3.77 9.05 9.43 2.93 4.93 2.94 2.59 malign +4.36 0.27 3.72 0.42 1.86 0.02 2.65 1.84 0.77 benign +9.45 9.29 5.11 2.81 2.85 9.17 3.11 2.14 1.12 malign +2.58 2.04 4.33 1.07 2.64 9.23 6.49 0.65 0.16 malign +9.22 7.72 7.87 1.65 2.97 3.65 7.57 6.16 7.48 malign +0.61 0.49 0.99 0.19 1.98 0.27 2.07 0.71 0.28 benign +7.76 3.99 6.55 0.85 2.47 9.12 2.68 8.65 1.92 malign +4.73 0.35 0.92 0.79 1.83 0.36 2.82 0.23 0.58 benign +2.22 2.38 4.31 1.46 2.14 9.49 6.58 0.90 0.59 malign +6.77 1.29 3.66 0.21 2.02 3.83 2.20 2.68 0.52 malign +2.08 0.40 0.64 0.59 1.74 0.43 2.02 1.47 0.10 benign +2.28 0.40 0.93 0.88 1.67 0.75 1.93 0.30 0.68 benign +0.66 0.84 0.49 0.34 1.25 0.58 1.66 0.79 0.81 benign +0.84 0.88 0.72 0.54 1.65 0.86 2.83 0.33 0.40 benign +9.77 4.91 6.55 2.06 2.22 6.35 2.12 2.22 7.99 malign +2.73 0.88 0.07 0.76 1.25 0.88 2.43 0.70 0.04 benign +1.20 0.99 0.19 1.72 1.96 0.77 2.08 0.38 0.14 benign +0.32 3.90 2.94 9.45 3.73 9.15 4.09 5.62 0.62 malign +9.73 3.84 5.25 0.33 1.55 9.33 4.67 2.78 0.97 malign +6.54 3.93 4.91 9.54 1.73 9.74 2.15 7.07 1.41 malign +7.53 9.14 9.75 9.22 7.81 9.15 9.27 6.86 2.18 malign +9.84 9.80 9.88 9.01 9.61 9.49 3.82 9.87 9.81 malign +2.59 0.34 0.67 0.62 2.48 0.98 1.87 0.17 0.10 benign +5.07 0.45 2.12 0.39 3.22 4.18 4.23 9.14 0.77 malign +4.27 5.70 5.83 7.51 5.29 9.22 3.38 9.45 3.22 malign +0.92 0.50 0.04 0.18 1.36 0.95 0.33 0.70 0.00 benign +0.95 0.63 0.17 0.10 1.36 0.02 2.69 0.90 0.69 benign +9.76 3.84 3.21 5.10 1.25 9.71 1.55 2.10 0.96 malign +4.57 4.94 6.19 7.08 5.61 9.98 6.19 3.57 0.42 malign +4.67 2.72 3.92 2.93 3.15 4.46 3.92 6.12 0.90 benign +7.96 1.86 0.39 0.07 4.17 0.69 0.15 0.07 0.59 benign +8.78 0.28 1.28 5.16 3.88 9.23 6.29 6.22 1.16 malign +7.59 3.12 9.92 4.78 3.76 3.16 6.85 9.86 0.56 malign +0.84 0.32 0.91 0.16 1.85 0.55 2.56 0.23 0.42 benign +9.78 9.93 9.92 6.32 8.65 9.61 6.34 9.08 9.83 malign +0.64 0.87 0.39 0.16 1.38 0.79 2.09 0.48 0.01 benign +7.53 2.96 3.49 8.30 2.25 9.63 2.94 2.90 0.22 malign +9.45 7.66 3.18 3.16 3.00 9.22 2.49 9.08 3.69 malign +0.78 0.84 0.21 0.77 1.56 0.19 2.39 0.21 0.13 benign +0.76 0.19 0.07 0.67 1.26 0.97 2.01 0.72 0.91 benign +6.05 7.80 6.02 5.67 3.71 2.77 7.54 7.32 3.52 malign +2.92 0.56 0.17 0.71 1.40 4.75 4.91 0.10 0.49 benign +1.04 0.87 0.22 0.90 2.48 0.76 1.88 0.93 0.09 benign +1.00 0.13 0.86 0.71 1.11 0.55 0.20 0.14 0.95 benign +7.26 5.33 3.01 9.30 9.32 0.69 2.46 4.81 0.92 malign +0.77 0.22 0.91 0.80 1.10 0.74 0.36 0.44 0.01 benign +0.89 0.92 0.02 0.08 0.63 0.29 1.40 0.63 0.22 benign +5.00 4.81 4.76 1.52 4.71 9.57 3.37 2.66 0.30 malign +5.25 7.01 6.56 7.04 5.93 7.33 7.90 8.61 0.45 malign +0.39 0.81 0.81 0.55 4.61 0.39 2.91 0.03 0.64 benign +3.01 3.06 3.52 3.42 5.58 4.39 6.46 2.25 0.09 benign +6.39 5.79 2.51 1.49 4.56 9.76 6.01 3.77 5.86 malign +2.21 0.81 0.17 0.38 1.27 0.02 2.86 0.82 0.82 benign +4.58 3.49 5.53 9.98 1.34 9.57 3.28 0.96 0.64 malign +0.14 0.15 0.47 0.82 1.71 0.19 2.22 0.55 0.49 benign +2.71 1.87 1.27 0.02 1.09 0.18 1.66 2.71 0.09 benign +9.82 0.46 0.83 0.61 1.32 9.93 4.55 3.21 0.20 malign +0.82 0.50 0.15 0.09 1.84 1.00 1.38 0.64 0.58 benign +7.69 9.99 2.77 1.98 5.08 3.14 3.00 9.65 0.67 malign +9.02 3.34 5.24 3.49 4.89 9.31 6.65 0.20 0.54 malign +9.02 3.46 6.05 1.06 1.02 7.25 5.13 0.23 0.76 malign +4.50 0.53 0.69 0.73 1.79 0.29 2.86 0.79 1.91 benign +4.22 1.51 1.62 1.26 1.61 0.42 1.77 2.00 0.75 benign +4.18 3.26 5.89 5.88 3.04 9.65 3.42 2.95 0.11 malign +7.81 5.12 6.20 2.28 2.47 9.44 2.89 3.41 1.97 malign +0.67 0.63 0.33 0.57 1.63 0.78 0.24 0.17 0.05 benign +5.88 4.83 4.48 7.11 3.16 9.82 2.64 3.49 0.60 malign +0.78 0.14 0.78 0.65 1.44 0.02 2.66 0.68 0.31 benign +0.74 0.68 0.98 0.05 0.90 0.46 1.74 0.51 0.60 benign +7.30 4.69 4.94 4.88 1.84 9.29 3.97 2.45 0.85 malign +9.49 2.42 2.45 0.39 1.69 9.90 6.84 5.13 0.77 malign +0.56 0.11 0.48 0.42 1.08 0.98 2.22 0.23 0.14 benign +1.64 0.98 0.58 0.76 1.27 0.09 0.65 0.06 0.17 benign +0.03 0.82 0.91 0.35 1.29 0.71 0.96 0.39 0.42 benign +6.20 5.58 3.64 7.96 9.50 9.87 8.02 4.78 2.99 malign +0.01 0.18 0.19 0.47 1.90 0.60 0.20 0.60 0.52 benign +4.84 1.58 1.01 1.18 2.52 0.84 0.80 2.34 0.64 benign +0.89 0.33 0.70 0.73 0.89 0.48 0.31 2.39 0.89 benign +2.75 3.21 3.64 9.85 4.46 0.92 2.36 2.47 0.31 malign +3.54 1.16 2.62 4.95 2.13 7.30 6.97 5.22 0.69 malign +4.43 0.86 0.21 2.41 1.69 0.27 0.70 0.80 0.84 benign +1.71 0.92 0.99 0.05 1.77 0.09 2.49 0.70 0.62 benign +2.61 3.24 4.39 2.12 6.34 2.25 3.45 5.05 0.53 benign +1.04 6.85 9.83 9.36 6.79 9.55 3.42 8.97 3.59 malign +0.38 0.96 0.81 0.23 1.75 0.97 1.11 0.54 0.77 benign +3.09 0.01 0.40 0.02 2.77 0.52 1.39 1.86 0.29 benign +4.27 2.28 2.60 0.67 2.08 2.39 2.10 2.20 2.82 malign +7.74 9.64 9.58 6.66 9.85 9.51 6.75 2.29 7.31 malign +7.12 9.31 4.40 2.90 7.32 3.75 3.53 9.65 2.51 malign +9.95 2.82 4.68 3.34 2.13 6.85 2.92 4.78 2.58 malign +5.40 9.73 9.93 9.75 9.42 9.82 7.40 9.14 9.31 malign +2.48 9.07 2.03 9.73 5.80 9.38 4.99 0.54 3.30 malign +2.95 1.91 1.69 0.47 3.33 2.85 1.36 0.59 0.70 benign +3.94 3.71 3.33 1.73 1.15 2.94 1.41 0.25 0.32 benign +1.48 0.84 0.42 0.79 1.05 0.14 2.79 0.95 0.74 benign +1.26 0.36 0.89 0.14 1.06 0.72 1.92 0.24 0.60 benign +5.35 9.98 9.55 9.02 7.99 9.61 6.61 9.96 6.21 malign +4.54 7.46 7.09 9.96 4.81 9.63 7.45 9.07 2.01 malign +0.32 0.46 2.73 0.76 1.18 0.65 0.70 0.52 0.79 benign +0.14 0.18 2.66 0.54 0.68 0.07 1.28 0.56 0.36 benign +3.12 2.40 1.66 0.26 2.50 0.03 1.25 0.22 0.89 benign +0.20 0.32 2.32 0.11 1.42 0.58 0.06 0.08 0.54 benign +3.72 0.21 1.40 0.65 1.55 0.14 1.54 0.65 0.74 benign +4.51 0.29 0.71 1.14 1.99 0.12 1.36 0.96 0.66 benign +2.94 0.15 1.91 0.32 1.71 0.89 1.95 0.53 0.92 benign +0.91 0.36 0.07 0.15 1.05 0.73 0.97 0.99 0.82 benign +0.60 0.51 0.71 0.56 1.61 0.39 1.42 0.93 0.77 benign +0.94 0.48 0.19 0.57 0.50 0.52 1.24 0.61 0.61 benign +2.90 0.77 0.24 3.74 2.32 0.23 1.19 1.12 0.94 benign +4.87 2.78 4.00 0.71 3.02 0.30 2.86 0.50 0.77 benign +0.82 0.31 0.56 0.64 1.33 0.30 0.13 0.17 0.20 benign +10.00 5.96 2.73 5.28 3.62 9.13 6.93 7.47 3.83 malign +2.22 1.48 1.05 1.71 1.35 0.95 2.75 1.70 0.31 benign +1.50 0.81 0.44 0.98 1.14 0.70 0.17 0.53 0.91 benign +1.87 0.80 0.55 0.58 1.36 0.92 0.41 0.59 0.52 benign +2.58 2.44 1.62 1.39 2.59 0.32 0.82 1.30 2.86 benign +6.74 5.46 5.65 2.55 1.57 9.42 6.03 0.02 0.35 malign +4.08 2.69 2.62 1.20 2.42 0.57 2.99 0.70 0.98 benign +1.72 0.37 0.16 0.52 1.55 0.68 1.68 1.06 0.59 benign +4.80 0.54 0.09 0.79 2.81 1.72 1.39 1.17 0.53 benign +0.14 0.66 0.69 1.42 1.39 0.99 1.23 0.72 0.19 benign +9.68 7.66 6.12 3.88 2.62 9.90 6.34 8.99 0.53 malign +2.34 0.77 0.12 0.62 1.45 0.29 2.00 0.71 0.62 benign +0.60 0.99 0.50 0.84 0.45 0.51 0.80 0.60 0.01 benign +0.31 1.94 2.75 0.96 1.92 0.91 1.92 0.73 0.63 benign +2.00 0.77 0.77 0.06 1.22 0.91 1.36 0.75 0.71 benign +2.80 0.31 0.83 0.19 1.44 0.33 2.54 0.28 0.20 benign +3.90 0.04 0.50 0.86 1.88 0.93 0.17 0.95 0.16 benign +2.84 1.75 0.78 0.17 1.33 0.60 1.54 1.79 0.88 benign +0.05 1.28 2.67 0.58 1.91 0.96 0.26 0.56 0.60 benign +2.70 9.22 7.49 6.44 5.84 8.02 8.55 2.88 7.23 malign +2.36 0.23 0.82 0.33 1.92 0.52 0.20 0.16 0.89 benign +4.05 2.33 2.24 0.66 1.59 0.35 1.84 0.58 0.56 benign +2.79 0.86 0.33 0.97 1.74 3.47 0.63 0.60 0.56 benign +0.40 1.34 0.33 2.88 1.30 0.65 0.35 1.99 0.86 benign +0.91 0.45 0.39 0.47 1.05 0.74 1.13 0.37 0.65 benign +3.63 1.96 1.76 0.24 1.61 0.63 1.93 0.18 0.23 benign +0.71 0.00 0.63 0.95 1.56 0.85 1.98 0.53 0.62 benign +1.82 2.32 1.20 1.82 1.37 1.58 2.36 0.85 0.16 benign +2.47 0.20 1.51 0.82 1.79 0.10 1.10 0.94 0.63 benign +0.74 0.86 0.03 0.59 1.81 0.86 1.45 0.88 0.97 benign +9.34 9.41 9.13 5.30 7.29 3.96 7.92 4.12 0.40 malign +4.30 0.89 1.93 0.90 1.66 0.68 2.95 0.98 0.14 benign +7.33 4.68 5.56 1.86 2.42 9.49 5.41 5.06 0.95 malign +2.68 2.85 1.41 5.92 2.76 2.74 2.19 4.83 0.21 benign +7.09 6.63 7.53 4.17 9.06 9.99 6.37 1.64 0.89 malign +0.28 0.94 0.26 0.09 1.60 0.97 1.89 0.57 0.10 benign +4.91 1.52 1.92 1.50 1.44 1.23 2.97 1.81 1.92 benign +1.66 2.39 0.61 0.86 4.29 0.14 0.48 0.61 0.80 benign +2.29 1.97 1.77 2.38 1.61 2.18 2.77 0.51 0.89 benign +9.52 9.89 9.93 6.59 9.06 9.07 7.63 1.64 0.25 malign +3.33 2.93 2.46 0.72 1.46 0.61 2.48 2.18 0.81 benign +4.96 0.05 2.90 0.89 1.22 0.45 1.03 0.37 0.86 benign +2.12 0.94 0.55 0.15 1.64 0.76 0.96 0.89 0.60 benign +8.61 9.60 9.85 9.67 9.24 9.53 9.92 9.01 0.46 malign +4.26 2.02 5.88 0.66 1.08 0.68 0.86 0.77 0.68 benign +7.27 6.58 7.40 1.13 3.42 1.79 4.28 9.23 0.36 malign +0.73 0.04 0.63 0.94 1.22 0.96 1.30 0.45 0.43 benign +2.00 0.41 0.50 0.61 1.65 0.24 1.56 0.79 0.48 benign +0.28 2.37 0.97 0.93 1.35 0.94 1.06 1.70 0.17 benign +4.74 0.71 0.84 2.12 3.29 0.29 2.75 1.11 0.60 benign +4.65 0.74 0.34 0.10 1.47 0.44 1.84 1.14 0.27 benign +2.04 1.04 1.12 2.53 1.08 0.55 0.71 0.11 0.17 benign +5.46 8.64 6.97 4.98 4.60 7.76 3.88 1.06 0.47 benign +9.41 7.29 9.25 0.36 2.63 9.92 4.92 0.26 0.52 malign +9.81 9.11 9.87 0.68 5.09 0.92 1.87 7.09 0.11 malign +3.36 0.72 0.39 0.66 1.39 0.09 0.77 0.57 0.96 benign +3.07 0.97 2.88 2.91 1.09 0.51 0.17 0.94 0.43 benign +4.20 0.42 0.96 0.52 1.90 0.22 0.66 0.88 0.21 benign +9.96 3.47 2.01 9.10 3.36 9.70 9.88 0.02 0.36 malign +4.32 1.96 1.50 3.23 1.49 3.41 0.66 0.80 0.79 benign +0.05 0.37 0.95 2.99 1.99 2.01 0.22 0.39 0.80 benign +0.95 0.19 0.38 0.22 1.44 1.38 0.62 0.16 0.48 benign +4.87 0.49 0.01 5.76 2.43 0.80 1.04 0.96 0.60 benign +1.61 0.65 0.18 0.42 1.56 0.29 0.81 0.39 0.22 benign +0.19 0.93 0.51 0.82 1.35 0.11 0.48 0.66 0.64 benign +4.05 0.52 0.36 0.52 1.45 0.64 0.22 0.80 0.67 benign +0.04 0.09 0.30 0.71 0.45 0.77 0.30 0.14 0.43 benign +4.30 6.00 8.77 7.22 5.15 9.32 7.55 9.64 0.00 malign +3.97 0.14 0.15 2.85 0.50 0.24 1.70 0.99 0.02 benign +4.37 0.82 0.12 0.41 1.77 0.33 0.34 0.50 0.91 benign +2.89 0.26 0.91 2.73 1.65 0.75 0.41 0.88 0.15 benign +3.63 4.23 4.65 7.52 5.63 9.77 9.09 6.53 0.06 malign +1.61 2.10 0.33 0.89 2.93 0.58 0.07 0.10 0.15 benign +9.85 1.77 1.09 0.18 1.71 5.35 0.89 0.08 1.97 malign +9.06 5.86 4.63 7.63 4.28 9.36 7.77 5.11 0.41 malign +7.30 7.79 8.41 5.09 5.41 2.52 9.60 9.53 0.72 malign +4.99 0.54 1.15 0.21 1.98 0.64 0.97 0.91 0.65 benign +4.78 0.48 2.67 0.58 1.58 0.69 0.79 0.02 0.71 benign +4.88 0.22 0.42 2.59 1.17 0.74 0.52 0.21 0.52 benign +2.15 0.06 0.88 0.36 1.98 4.07 0.17 0.03 0.79 benign +5.82 0.33 0.51 2.26 1.31 0.06 0.76 0.31 0.55 benign +3.80 0.06 0.73 0.78 1.02 0.83 0.75 1.00 0.43 benign +3.86 0.65 0.28 0.29 1.71 0.15 0.08 0.02 0.09 benign +9.59 8.49 7.88 6.90 5.44 3.59 6.25 9.38 2.57 malign +9.64 5.89 5.31 1.34 3.15 9.28 8.12 6.93 0.16 malign +5.77 5.12 5.59 4.44 3.76 9.84 6.45 5.89 1.73 malign +3.68 0.62 0.49 0.71 1.10 0.27 0.31 0.04 0.14 benign +0.56 0.30 1.67 0.74 1.11 0.25 1.38 0.57 0.89 benign +2.36 0.65 0.95 0.28 0.63 0.55 1.36 0.64 0.64 benign +5.08 0.99 0.62 2.98 1.37 0.24 0.31 0.27 0.04 benign +5.21 0.88 0.60 0.39 0.37 0.13 0.06 0.79 0.52 benign +3.07 0.46 0.33 0.03 1.21 0.35 0.27 0.26 0.54 benign +4.92 0.77 0.65 0.38 1.12 0.86 0.63 0.12 0.50 benign +2.29 0.72 0.17 0.30 1.85 0.18 0.89 0.99 0.62 benign +3.66 0.79 1.82 0.77 1.17 0.24 0.52 0.71 0.90 benign +3.41 0.41 0.25 0.74 1.93 0.75 0.22 0.70 0.51 benign +4.69 1.54 0.21 0.83 1.25 0.92 0.03 0.31 0.09 benign +3.79 7.77 6.12 9.55 3.18 9.35 6.11 4.60 0.43 malign +4.77 0.58 0.28 0.02 0.02 0.83 0.33 0.28 0.66 benign +4.82 2.82 1.77 3.39 1.79 0.67 0.17 0.68 0.38 benign +8.40 9.45 9.21 9.78 9.85 4.38 9.08 9.78 9.60 malign +7.13 6.51 7.76 4.27 4.64 9.09 8.63 9.66 0.87 malign +4.69 0.50 1.83 0.46 1.36 0.80 0.07 0.76 0.66 benign +0.01 0.18 0.58 2.80 0.68 2.54 0.05 0.90 0.35 benign +2.09 0.94 0.51 0.80 0.55 0.52 1.27 0.11 0.93 benign +9.75 9.49 9.80 9.48 5.05 9.95 7.63 0.05 4.05 malign +2.23 5.69 3.32 9.64 2.11 2.76 2.96 3.04 0.89 malign +5.16 2.78 1.42 0.48 2.52 3.50 3.97 0.15 0.39 malign +0.76 0.96 0.27 0.06 1.36 0.55 0.74 0.78 0.26 benign +4.15 7.23 8.38 3.01 2.62 9.68 6.04 0.51 0.74 malign +3.29 0.34 0.71 0.65 0.41 0.61 1.47 0.13 0.51 benign +4.55 9.88 9.39 9.88 5.76 9.39 5.16 4.80 1.49 malign +4.74 0.83 1.95 9.82 3.72 4.56 1.38 0.02 0.37 benign +2.19 0.02 0.40 0.86 0.09 0.73 1.02 0.22 0.66 benign +0.86 0.02 0.55 0.65 0.30 0.28 0.62 0.70 0.28 benign +3.08 1.53 0.77 0.18 1.92 0.25 0.89 0.92 0.12 benign +3.31 0.38 0.32 0.98 1.49 0.11 1.64 0.40 0.59 benign +3.50 0.94 0.38 0.53 1.62 0.65 1.18 0.38 0.87 benign +5.96 0.32 0.54 0.41 1.29 0.14 2.35 0.33 0.75 benign +3.32 0.83 0.91 0.14 1.92 0.07 1.16 0.91 0.62 benign +3.05 0.98 0.10 1.21 1.81 0.61 1.61 0.89 0.57 benign +3.65 0.72 0.57 0.05 1.39 0.04 2.23 0.77 0.38 benign +0.15 0.56 0.74 0.55 1.26 0.41 0.43 0.77 0.54 benign +2.23 2.08 0.29 0.51 1.73 0.51 0.54 0.44 0.13 benign +7.63 9.60 9.94 9.47 6.37 4.97 3.05 7.09 6.99 malign +0.24 0.41 0.54 0.18 1.83 3.26 0.88 0.52 0.55 benign +4.05 0.26 0.39 0.15 1.09 0.73 0.01 0.10 0.43 benign +1.98 0.47 0.83 0.37 1.68 0.13 0.98 0.73 0.38 benign +0.08 0.37 0.90 0.31 1.15 0.98 0.98 0.50 0.42 benign +4.32 0.97 0.42 0.97 1.55 0.56 1.41 0.16 0.11 benign +4.24 0.55 0.60 0.27 1.41 0.68 0.41 0.06 0.77 benign +2.18 0.13 0.74 0.93 0.21 0.17 1.11 0.87 0.10 benign +5.50 5.64 6.33 9.64 2.69 9.23 7.11 9.16 1.79 malign +3.64 9.11 3.70 7.00 2.63 9.81 8.87 9.54 0.62 malign +0.87 0.84 0.90 0.70 0.55 0.17 0.11 0.07 0.37 benign +0.50 0.41 0.31 0.64 0.49 0.82 1.22 0.21 0.37 benign +2.92 0.80 1.83 1.92 1.92 0.72 0.99 0.92 0.51 benign +3.68 6.05 7.46 2.59 3.17 9.68 8.79 0.64 0.62 malign +0.57 0.06 0.85 0.41 2.17 0.49 0.32 0.78 0.14 benign +3.51 0.45 0.83 0.01 2.38 0.83 0.99 0.46 0.87 benign +9.76 3.88 4.80 3.18 2.12 4.74 6.59 2.61 0.99 malign +6.35 4.14 6.00 9.75 3.29 9.87 4.19 2.63 0.58 malign +2.31 0.31 0.49 0.88 1.95 0.73 1.10 0.55 0.65 benign +2.82 0.78 0.15 1.52 1.58 0.31 0.14 0.59 0.40 benign +3.96 0.33 0.83 0.59 1.76 0.31 0.68 0.02 0.38 benign +3.43 0.34 0.90 0.99 1.47 0.88 2.25 0.27 0.22 benign +5.88 0.04 2.68 1.82 1.79 0.83 0.70 0.19 0.88 benign +3.70 0.40 0.19 0.81 0.64 0.83 1.41 0.67 0.64 benign +6.66 3.27 3.93 2.95 3.37 9.81 5.28 8.58 0.22 malign +3.13 1.13 1.52 0.06 1.29 0.90 1.58 0.91 0.48 benign +0.05 0.89 0.60 0.17 0.30 0.21 2.29 0.39 0.82 benign +2.86 0.03 0.35 0.30 1.32 0.71 1.77 0.85 0.79 benign +1.71 0.99 0.78 0.41 1.52 0.05 1.20 0.09 0.01 benign +0.34 0.84 2.15 1.32 1.74 0.90 2.49 0.79 0.02 benign +4.88 0.54 0.80 0.61 1.96 0.93 2.48 0.07 0.55 benign +4.84 0.42 1.97 0.05 1.10 0.11 2.95 0.44 0.70 benign +3.08 0.50 0.81 0.24 1.71 0.81 1.54 0.13 0.22 benign +5.34 0.26 0.34 0.50 1.64 0.83 1.80 0.01 0.51 benign +4.53 0.50 0.21 0.50 1.27 1.46 1.24 0.75 0.93 benign +2.24 0.12 0.28 0.16 1.91 0.50 0.81 0.12 0.41 benign +4.15 2.26 0.90 0.55 1.78 0.12 0.55 0.35 0.06 benign +3.86 0.23 0.18 0.13 1.24 0.22 1.87 0.17 0.19 benign +1.18 0.04 2.19 1.43 1.88 0.12 1.67 0.80 0.48 benign +4.47 0.09 0.01 0.14 1.60 0.22 1.90 0.68 0.76 benign +5.44 9.13 9.16 9.23 3.26 9.21 6.12 9.49 0.71 malign +1.93 0.16 0.89 0.75 0.73 0.85 0.60 0.55 1.00 benign +2.68 0.05 0.09 0.52 0.23 0.03 0.80 0.91 0.43 benign +6.17 7.30 2.23 6.15 3.59 4.90 6.54 7.37 1.54 malign +2.69 0.00 0.17 0.68 1.45 0.59 1.10 0.30 0.93 benign +0.76 0.67 0.90 0.86 1.94 0.35 2.95 0.20 0.72 benign +2.10 1.21 1.51 1.89 1.73 0.28 3.06 1.27 0.18 benign +3.93 3.10 1.07 0.52 1.37 4.02 1.73 0.76 1.66 benign +2.71 0.51 0.89 0.30 1.70 0.97 0.31 0.43 0.58 benign +3.87 2.05 0.66 0.52 1.18 0.10 3.94 7.60 0.14 benign +4.51 1.90 1.98 1.64 0.21 0.18 1.13 0.73 0.54 benign +4.45 0.00 0.08 2.06 1.82 0.56 0.36 0.65 0.30 benign +1.92 0.72 0.19 0.68 1.39 0.87 1.60 0.14 0.37 benign +4.69 0.49 0.58 0.36 1.19 0.47 1.55 0.71 0.50 benign +4.02 0.95 0.44 0.33 1.16 0.84 2.53 0.59 0.22 benign +4.66 0.46 0.88 0.41 1.17 0.83 2.20 0.56 0.26 benign +0.04 0.72 0.84 0.28 1.05 0.61 2.39 0.57 0.19 benign +2.66 0.47 0.52 0.71 1.91 0.90 1.45 0.64 0.67 benign +3.90 0.43 0.35 0.68 1.25 0.96 2.13 1.50 0.07 benign +4.31 6.89 9.12 9.81 4.96 9.32 9.78 9.74 0.73 malign +2.64 0.58 1.17 0.36 1.35 0.65 2.41 0.09 0.66 benign +3.19 0.17 0.75 0.15 1.42 2.70 1.58 0.45 0.42 benign +7.71 3.20 3.52 0.47 5.56 9.68 1.91 4.19 1.66 malign +9.40 9.61 7.33 9.08 5.85 4.92 9.19 2.53 0.45 malign +7.35 9.03 3.48 3.67 7.46 9.35 7.34 1.45 0.31 malign +6.98 5.24 9.57 4.81 2.14 9.71 8.56 9.62 1.48 malign +2.82 0.34 0.03 0.29 1.29 0.40 1.53 0.22 0.82 benign +0.60 0.53 0.63 0.41 1.94 0.05 1.28 0.90 0.60 benign +9.35 8.86 6.36 2.46 3.99 1.79 6.19 6.38 0.92 malign +4.98 0.73 1.98 0.45 1.01 0.48 2.61 0.70 0.37 benign +4.21 0.72 0.67 0.03 1.80 0.50 1.99 0.89 0.72 benign +0.17 0.20 0.20 0.09 1.72 0.35 1.42 0.56 0.09 benign +0.75 0.87 0.22 0.00 1.45 0.55 1.08 0.86 0.04 benign +0.89 0.20 0.24 0.87 1.90 0.08 2.85 0.95 0.54 benign +4.84 0.95 1.02 0.27 1.99 0.76 1.48 0.52 0.04 benign +4.23 6.29 9.80 5.37 4.93 9.36 6.58 4.96 0.37 malign +5.08 9.08 4.90 4.68 3.55 9.74 5.56 9.83 0.16 malign +2.03 0.55 0.25 0.40 1.17 0.49 0.03 0.88 0.84 benign +4.66 0.90 0.56 5.41 2.06 0.20 0.32 0.95 0.58 benign +0.39 1.00 0.36 0.32 1.57 0.19 0.59 0.56 0.75 benign +7.46 9.44 9.56 9.35 5.57 9.50 9.38 9.14 0.66 malign +4.41 0.65 0.14 0.37 1.49 0.98 1.13 1.04 0.41 benign +8.12 7.86 7.79 8.08 5.21 2.20 3.68 0.88 0.64 malign +4.75 0.75 0.94 0.28 1.28 0.29 0.58 0.90 0.62 benign +3.10 9.73 7.91 4.64 3.09 0.11 9.62 0.94 0.26 malign +1.39 4.32 6.90 5.75 3.62 9.09 6.03 5.87 0.20 malign +9.50 2.56 3.17 4.33 2.18 9.30 3.08 0.12 0.48 malign +4.40 0.46 1.14 0.55 1.34 0.04 0.47 0.09 0.40 benign +3.43 7.62 5.29 2.19 3.95 9.40 6.62 0.47 0.24 malign +4.68 0.30 0.58 0.31 1.55 0.62 1.34 0.50 0.44 benign +3.44 0.83 1.17 0.25 1.67 0.69 1.76 0.28 0.49 benign +4.18 0.92 2.97 0.89 1.36 0.73 2.93 0.56 0.57 benign +2.13 0.44 0.69 0.27 1.31 0.78 1.84 0.50 0.14 benign +4.76 1.33 3.45 0.89 0.42 0.46 0.18 0.94 0.07 benign +2.61 0.85 0.66 0.81 1.95 0.81 1.04 0.10 0.84 benign +0.64 0.72 0.18 0.19 0.77 0.39 1.49 0.87 0.85 benign +3.63 0.07 0.60 0.68 1.71 0.24 1.74 0.67 0.32 benign +4.99 3.22 5.61 7.11 3.48 0.78 7.49 9.00 0.17 malign +4.17 2.52 1.53 7.76 4.96 9.35 7.02 0.02 1.79 malign +9.48 4.61 9.62 2.51 4.63 7.04 6.13 7.15 2.27 malign +3.40 0.53 0.75 1.74 1.31 0.96 0.16 0.66 0.15 benign +0.68 0.33 0.33 0.42 1.49 0.55 0.54 0.07 0.42 benign +4.79 9.67 9.09 9.47 9.96 9.55 9.27 0.40 0.67 malign +4.10 0.33 0.67 0.16 1.12 0.24 0.62 0.10 0.12 benign +9.13 3.50 2.71 9.47 2.51 9.57 6.97 0.50 1.86 malign +4.99 9.10 9.06 9.49 4.87 1.02 7.93 4.49 0.10 malign +7.78 9.60 9.63 9.54 5.76 9.48 9.20 9.62 9.39 malign +1.95 2.71 0.92 0.00 1.29 0.50 1.79 0.05 0.88 benign +1.81 0.56 0.40 0.13 0.86 0.66 1.53 0.78 0.52 benign +3.86 0.20 2.44 0.06 1.82 0.82 1.73 0.41 0.76 benign +2.47 0.44 0.13 0.32 1.80 0.14 1.72 0.03 0.75 benign +3.55 0.94 0.17 0.08 1.02 0.34 1.87 0.13 0.58 benign +4.38 0.75 0.48 0.94 1.83 1.00 1.90 0.98 0.77 benign +2.07 0.86 0.60 0.69 1.30 0.41 1.84 0.68 0.49 benign +5.14 2.55 2.80 2.48 2.71 1.46 5.48 0.78 0.30 benign +6.58 0.34 1.98 2.54 1.28 0.51 1.63 0.98 0.94 benign +0.26 0.68 0.20 0.32 1.37 0.57 0.89 0.53 0.93 benign +4.72 0.40 0.81 1.85 0.78 0.44 1.63 0.36 0.41 benign +2.49 0.14 2.65 0.81 2.67 3.79 0.36 0.33 0.37 benign +3.47 5.93 5.49 4.41 6.04 5.21 6.27 6.93 2.91 malign +1.09 0.79 0.23 0.74 1.69 4.75 0.31 0.41 0.92 benign +1.94 0.15 0.31 0.73 1.74 0.90 0.78 0.44 0.30 benign +3.10 0.20 0.96 0.45 2.00 0.86 0.35 0.71 0.39 benign +5.64 1.16 2.43 0.95 1.30 0.79 0.09 0.88 0.87 benign +4.88 0.28 0.86 0.19 1.29 0.17 1.64 0.18 0.82 benign +0.85 0.85 0.31 0.34 1.12 0.78 0.73 0.82 0.50 benign +7.92 6.40 3.57 3.07 4.65 2.61 4.01 9.50 0.52 malign +2.44 0.89 0.25 0.55 1.01 0.70 0.53 0.20 0.40 benign +2.20 0.38 3.77 0.72 1.01 0.59 0.18 0.14 0.01 benign +9.66 9.74 6.44 7.72 6.81 0.10 9.04 9.48 2.33 malign +3.40 1.62 3.73 2.34 1.53 1.57 1.95 0.53 0.92 benign +3.63 0.06 0.25 0.74 1.84 0.36 0.70 0.98 0.31 benign +4.72 0.04 0.46 2.62 1.39 0.50 0.70 0.86 0.92 benign +3.88 0.27 0.59 2.29 1.07 0.90 0.57 0.49 0.98 benign +2.31 0.42 0.58 0.67 1.48 0.69 1.95 0.87 0.13 benign +2.72 0.34 0.18 0.81 1.60 0.63 1.74 0.77 0.27 benign +0.24 0.34 0.11 0.12 1.25 0.16 0.77 0.28 0.82 benign +1.68 0.35 0.01 0.76 1.04 0.26 0.09 0.21 0.30 benign +2.28 0.62 0.54 0.40 1.72 1.00 1.54 0.77 0.89 benign +0.37 1.83 1.17 0.11 1.65 0.16 0.68 0.39 0.57 benign +0.40 0.91 0.63 2.88 1.77 0.12 0.17 0.46 0.82 benign +4.23 9.17 9.57 9.85 9.79 1.45 9.24 9.94 9.12 malign +2.65 0.32 0.31 0.53 1.36 0.51 1.40 0.36 0.70 benign +2.93 0.12 0.18 1.21 2.87 3.11 0.48 0.10 0.00 benign +0.15 1.54 0.43 2.50 1.19 0.38 1.86 0.58 0.16 benign +4.19 0.90 0.94 0.33 1.52 0.39 1.01 1.59 0.93 benign +3.26 0.15 0.16 0.59 1.39 0.66 1.22 0.07 0.90 benign +2.80 0.78 1.00 0.29 1.79 0.86 2.82 0.13 0.96 benign +2.07 0.82 0.12 0.75 1.81 0.58 1.92 0.71 0.75 benign +4.73 0.69 0.30 0.51 1.65 0.07 1.45 0.45 0.98 benign +4.20 3.71 4.45 0.11 7.34 0.08 2.17 5.64 0.53 benign +6.49 7.32 7.27 6.75 2.02 9.55 6.60 1.84 2.40 malign +0.50 0.33 0.27 0.93 1.43 0.94 0.98 0.13 0.64 benign +0.20 0.89 0.56 0.12 1.78 0.70 1.95 0.24 0.09 benign +3.33 0.46 0.86 0.59 1.81 0.33 2.00 0.84 0.75 benign +0.39 0.56 2.50 0.11 1.64 0.12 1.36 0.66 0.01 benign +0.15 0.57 2.90 0.54 1.96 0.58 1.42 0.14 0.51 benign +2.75 0.97 0.49 3.00 1.25 0.98 1.12 0.93 0.26 benign +0.18 0.77 0.05 0.63 1.50 0.94 0.60 0.77 0.38 benign +4.06 1.14 1.78 1.95 1.50 0.85 0.87 0.45 1.18 benign +2.39 0.23 0.05 0.62 1.49 0.09 2.10 0.01 0.18 benign +4.49 6.61 3.33 0.01 5.57 0.90 6.17 9.12 2.77 malign +4.13 9.30 9.16 7.67 4.02 4.48 6.13 9.38 0.30 malign +2.54 9.52 6.03 7.08 4.47 7.57 6.38 3.68 0.70 malign +2.63 1.06 0.34 1.65 1.57 0.98 2.05 0.80 0.26 benign +1.97 0.58 0.97 0.38 1.55 0.29 2.05 0.39 0.02 benign +4.26 2.08 1.96 0.62 2.83 0.55 0.21 0.80 0.23 benign +0.88 0.61 0.01 0.38 1.62 0.60 1.29 0.66 0.05 benign +3.45 0.11 3.93 0.79 1.69 0.35 0.57 0.00 0.34 benign +0.15 0.88 1.15 0.04 1.60 0.94 1.20 0.72 0.52 benign +4.25 0.50 0.42 0.98 1.02 0.29 0.34 0.03 0.54 benign +0.28 0.02 0.25 0.76 1.33 0.59 0.05 0.90 0.05 benign +1.08 0.87 0.07 0.22 1.55 0.06 0.97 0.59 0.46 benign +9.37 9.88 9.34 9.83 4.21 9.38 9.36 9.75 6.20 malign +4.64 9.71 9.73 9.13 3.45 9.67 4.31 5.02 2.63 malign +4.08 0.69 0.14 0.78 1.68 0.96 2.62 1.55 0.19 benign +0.68 0.01 0.20 0.04 1.29 0.55 0.87 0.11 0.91 benign +1.00 0.95 0.52 0.45 1.17 0.42 0.64 0.18 0.07 benign +0.17 0.78 0.31 0.60 1.85 0.78 0.27 0.53 0.48 benign +0.54 0.03 0.05 0.14 1.85 0.26 0.05 0.72 0.74 benign +2.29 0.32 0.78 0.17 1.65 0.05 1.59 2.72 0.69 benign +3.86 0.64 0.67 0.81 1.52 0.17 0.30 0.70 0.28 benign +0.84 0.22 0.40 0.03 1.79 0.48 0.14 0.02 7.53 benign +0.86 0.99 0.54 2.60 1.49 0.22 0.89 0.29 0.82 benign +4.40 9.52 9.20 4.03 3.68 4.06 3.73 3.89 0.48 malign +2.99 0.21 0.91 0.10 1.92 0.85 0.45 0.83 0.33 benign +2.12 0.42 0.13 0.43 1.25 0.43 1.41 0.51 1.31 benign +2.89 0.03 0.64 0.08 2.70 1.96 0.16 0.86 0.58 benign +1.21 0.70 0.13 0.48 1.57 0.21 0.95 0.16 0.83 benign +4.36 9.41 9.54 2.05 6.30 2.20 7.06 9.51 1.80 malign +3.66 7.68 5.79 3.25 2.39 3.28 9.27 5.93 0.17 malign +3.91 7.88 8.00 4.35 3.70 4.53 9.25 3.32 1.00 malign diff --git a/pyminer2/tests/datasets/cyber-security-breaches.tab b/pyminer2/tests/datasets/cyber-security-breaches.tab new file mode 100644 index 0000000000000000000000000000000000000000..d0efad4ca269c40a4743ada06e1c03bea35c4832 --- /dev/null +++ b/pyminer2/tests/datasets/cyber-security-breaches.tab @@ -0,0 +1,1288 @@ +Name_of_Covered_Entity US State Business_Associate_Involved Individuals_Affected Type_of_Breach Location_of_Breached_Information Date_Posted_or_Updated Summary breach_start breach_end + d c d d t t t + +Brooke Army Medical Center TX 1000 Theft Paper 2014-06-30 A binder containing the protected health information (PHI) of up to 1,272 individuals was stolen from a staff member's vehicle. The PHI included names, telephone numbers, detailed treatment notes, and possibly social security numbers. In response to the breach, the covered entity (CE) sanctioned the workforce member and developed a new policy requiring on-call staff members to submit any information created during their shifts to the main office instead of adding it to the binder. Following OCR's investigation, the CE notified the local media about the breach. 2009-10-16 +Mid America Kidney Stone Association, LLC MO 1000 Theft Network Server 2014-05-30 Five desktop computers containing unencrypted electronic protected health information (e-PHI) were stolen from the covered entity (CE). Originally, the CE reported that over 500 persons were involved, but subsequent investigation showed that about 260 persons were involved. The ePHI included demographic and financial information. The CE provided breach notification to affected individuals and HHS. Following the breach, the CE improved physical security by installing motion detectors and alarm systems security monitoring. It improved technical safeguards by installing enhanced antivirus and encryption software. As a result of OCR's investigation the CE updated its computer password policy. 2009-09-22 +Alaska Department of Health and Social Services AK 501 Theft Other Portable Electronic Device, Other 2014-01-23 2009-10-12 +Health Services for Children with Special Needs, Inc. DC 3800 Loss Laptop 2014-01-23 "A laptop was lost by an employee while in transit on public transportation. The computer contained the protected health information of 3800 individuals. The protected health information involved in the breach included names, Medicaid ID numbers, dates of birth, and primary physicians. In response to this incident, the covered entity took steps to enforce the requirements of the Privacy & Security Rules. The covered entity has installed encryption software on all employee computers, strengthened access controls including passwords, reviewed and updated security policies and procedures, and updated it risk assessment. In addition, all employees received additional security training. + +" 2009-10-09 +L. Douglas Carlson, M.D. CA 5257 Theft Desktop Computer 2014-01-23 "A shared Computer that was used for backup was stolen on 9/27/09 from the reception desk area of the covered entity. The Computer contained certain electronic protected health information (ePHI) of 5,257 individuals who were patients of the CE. The ePHI involved in the breach included names, dates of birth, and clinical information, but there were no social security numbers, financial information, addresses, phone numbers, or other ePHI in any of the reports on the disks or the hard drive on the stolen Computer. Following the breach, the covered entity notified all 5,257 affected individuals and the appropriate media; added technical safeguards of encryption for all ePHI stored on the USB flash drive or the CD used on the replacement computer; added physical safeguards by keeping new portable devices locked when not in use in a secure combination safe in doctor's private office or in a secure filing cabinet; and added administrative safeguards by requiring annual refresher retraining of CE staff for Privacy and Security Rules as well as requiring immediate retraining of cleaning staff in both Rules. + +" 2009-09-27 +David I. Cohen, MD CA 857 Theft Desktop Computer 2014-01-23 "A shared Computer that was used for backup was stolen from the reception desk area, behind a locked desk area, probably while a cleaning crew had left the main door to the building open and the door to the suite was unlocked and perhaps ajar. The Computer contained certain electronic protected health information (ePHI) of 857 patients. The ePHI involved in the breach included names, dates of birth, and clinical information. Following the breach, the covered entity notified all affected individuals and the media, added technical safeguards of encryption for all ePHI stored on the USB flash drive or the CD used on the replacement computer, added physical safeguards by keeping new portable devices locked when not in use in a secure combination safe in doctor's private office or in a secure filing cabinet, and added administrative safeguards by requiring annual refresher retraining staff for Privacy and Security Rules as well as requiring immediate retraining of cleaning staff in both Rules, which has already taken place. + +" 2009-09-27 +Michele Del Vicario, MD CA 6145 Theft Desktop Computer 2014-01-23 "A shared Computer that was used for backup was stolen on 9/27/09 from the reception desk area of the covered entity. The Computer contained certain electronic protected health information (ePHI) of 6,145 individuals who were patients of the CE, The ePHI involved in the breach included names, dates of birth, and clinical information, but there were no social security numbers, financial information, addresses, phone numbers, or other ePHI in any of the reports on the disks or the hard drive on the stolen Computer. Following the breach, the CE: notified all 6,145 affected individuals and the appropriate media; added technical safeguards of encryption for all ePHI stored on the USB flash drive or the CD used on the replacement computer; all passwords are strong; all computers are password protected; added physical safeguards by keeping new portable devices locked when not in use in a secure combination safe in doctor's private office or in a secure filing cabinet; and added administrative safeguards by requiring annual refresher retraining of CE staff for Privacy and Security Rules as well as requiring immediate retraining of cleaning staff in both Rules, which has already taken place. + +" 2009-09-27 +Joseph F. Lopez, MD CA 952 Theft Desktop Computer 2014-01-23 "A shared Computer that was used for backup was stolen on 9/27/09. The Computer contained certain electronic protected health information (ePHI) of 952 patients. Following the breach, the covered entity notified all 952 affected individuals and the appropriate media; added technical safeguards of encryption for all ePHI stored on the USB flash drive or the CD used on the replacement computer; added physical safeguards by keeping new portable devices locked when not in use in a secure combination safe in doctor's private office or in a secure filing cabinet; and added administrative safeguards by requiring annual refresher retraining of staff for Privacy and Security Rules. + +" 2009-09-27 +Mark D. Lurie, MD CA 5166 Theft Desktop Computer 2014-01-23 "A shared Computer that was used for backup was stolen on 9/27/09 from the reception desk area of the covered entity. The Computer contained certain electronic protected health information (ePHI) of 5,166 individuals who were patients of the CE, The ePHI involved in the breach included names, dates of birth, and clinical information, but there were no social security numbers, financial information, addresses, phone numbers, or other ePHI in any of the reports on the disks or the hard drive on the stolen Computer. Following the breach, the CE: notified all 5,166 affected indiv's and the appropriate media; added technical safeguards of encryption for all ePHI stored on the USB flash drive or the CD used on the replacement computer; all passwords are strong; all computers are password protected; added physical safeguards by keeping new portable devices locked when not in use in a secure combination safe in doctor's private office or in a secure filing cabinet; and added administrative safeguards by requiring annual refresher retraining of CE staff for Privacy and Security Rules as well as requiring immediate retraining of cleaning staff in both Rules, which has already taken place. + +" 2009-09-27 +City of Hope National Medical Center CA 5900 Theft Laptop 2014-01-23 "A laptop computer was stolen from a workforce member's car. The laptop computer contained the protected health information of approximately 5,900 individuals. Following the breach, the covered entity encrypted all protected health information stored on lap tops. Additionally, OCR's investigation resulted in the covered entity improving their physical safeguards and retraining employees. + +" 2009-09-27 +The Children's Hospital of Philadelphia PA 943 Theft Laptop 2014-01-23 2009-10-20 +Cogent Healthcare of Wisconsin, S.C. TN 6400 Theft Laptop 2014-04-23 A laptop was stolen from a locked office at the Aurora St. Lukes Medical Center. The laptop contained protected health information pertaining to 6,400 individuals. The information included patient names, dates of birth, social security numbers, medical record numbers, and in some cases diagnosis codes. In response to the theft, the hospital implemented several corrective action measures, including accelerated efforts to encrypt all laptop hard drives, improved physical locks on the office where the theft occurred, staff training regarding the appropriate use and storage of devices containing ePHI, and encryption of portable flash drives and Blackberry devices. 2009-10-11 +Universal American NY Democracy Data & Communications, LLC ( 83000 Other Paper 2014-01-23 "In its breach report and during the course of OCR's investigation, the covered entity advised that it took various corrective actions to prevent a reoccurrence of the breach. Specifically, the covered entity conducted a risk assessment which revealed that the breach posed a significant risk of financial, reputational, or other harm to the 83,000 members. The covered entity sent notification letters to 83,000 members apologizing for the breach and offered a year of free credit monitoring and a $25,000 insurance policy against identity theft ($10,000 for New York residents). The covered entity also provided training to its call centers on November 29, 2009 to answer inquiries from callers concerned about the breach. In addition, media outlets were contacted to alert of a breach in states in which more than 500 members were impacted by the breach. The covered entity advised that media outlets were identified based on location of membership impacted, as well as ensuring it was a major media outlet and press releases were sent to 21 major media outlets on December 18, 2009. The covered entity also created and implemented a new policy titled 'Personal Health Information and Personal Identifiable Information Data Security and Handling Policy Acknowledgement Form' that centralized all data requests through a 'Team Track' which is an internal electronic submission request that ensures all PHI requested data receives the sign off of the Privacy Officer and Security Officer prior to release. Further, the covered entity also provided a mandatory annual computer-based training to all staff in May 2010. + +" 2009-11-12 +Kern Medical Center CA 596 Theft Other 2014-01-23 2009-10-31 +Keith W. Mann, DDS, PLLC NC Rick Lawson, Professional Computer Services 2000 Hacking/IT Incident Desktop Computer, Network Server, Electronic Medical Record 2014-01-23 2009-12-08 +Detroit Department of Health and Wellness Promotion MI 10000 Theft Other Portable Electronic Device 2014-01-23 2009-10-22 +Detroit Department of Health and Wellness Promotion MI 646 Theft Laptop, Desktop Computer 2014-01-23 "A desktop and four laptop computers were stolen from the covered entity's locked facility. The protected health information involved in the breach included names, addresses, dates of birth, social security numbers, types of services received, and Medicare/Medicaid numbers.Following the breach, the covered entity installed new office door locks with assigned keys, installed security cameras with alarms, and physically secured computers to desks. The covered entity now stores billing information in its patient management system, and it ensured that no electronic protected health information was stored locally. Additionally, OCR's investigation resulted in the covered entity providing training to workforce members regarding the incident + +" 2009-11-26 +University of California, San Francisco CA 610 Other E-mail 2014-01-23 2009-09-22 +Daniel J. Sigman MD PC MA 1860 Theft Other Portable Electronic Device, Other, Electronic Medical Record 2014-01-23 "Computer backup tapes containing EPHI for the office practice management program including electronic medical records were stolen from the home of the practice manager on December 11, 2009. The breach affected approximately 1,860 patients. The protected health information on the tapes contained patients' names, addresses, telephone numbers, dates of birth, insurance information, social security numbers and medical record information. Following the breach, Sigman took the following voluntary corrective actions: (1) upgraded software application for backup security; implemented a new external backup system in case the server goes down; (2) encryption software was implemented for data contained on both its backup tapes and network storage device; (3) revised its security policy for transporting backup media; backup tapes must now be stored in a lockbox within a locked office in its facility; the revised policy also prohibits the movement of backup tapes from the facility as well as restricts access to the tapes to designated workforce; (4) employees were retrained on the policies and procedures in place and received training on the new policies and procedures for safeguarding backup tapes; (5) notified affected individuals and the media. + +" 2009-12-11 +Massachusetts Eye and Ear Infirmary MA 1076 Theft Other 2014-01-23 2009-11-10 +BlueCross BlueShield Association DC Service Benefits Plan Administrative Services Corp 3400 Theft Paper 2014-06-30 "The covered entity's (CE) business associate (BA) incorrectly updated contract holders' addresses and mailed protected health information (PHI) to the wrong address of approximately 3,400 individuals. The PHI involved included demographic information, explanations of benefits, clinical information, and diagnoses. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. Upon discovery of the breach, the CE obtained assurances that the BA took steps to enforce the requirements of the BA agreement. Specifically, the BA updated its processes and created an incident tracking report. In addition, a contract was executed for a new vendor to handle mail address verification. Following OCR's investigation, the BA improved its code review process to catch the system error that caused this incident and instituted a manual quality review process. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2009-10-26 +BlueCross BlueShield Association DC Merkle Direct Marketing 15000 Theft Paper 2014-04-24 The covered entity's (CE) business associate (BA) mailed protected health information (PHI) of approximately 15,000 individuals to incorrect addresses due to an error in its quarterly address update process. The mailing contained demographic information, explanations of benefits, clinical information, and diagnoses. Upon discovery of the breach, the CE collected the returned mail and verified that it had not been delivered, and updated its HIPAA policies and procedures. Following OCR's investigation, the CE was able to recover all or nearly all of the misdirected envelopes. 2009-10-07 +Kaiser Permanente Medical Care Program CA 15500 Theft Other Portable Electronic Device, Other 2014-01-23 2009-12-01 +Blue Island Radiology Consultants IL United Micro Data 2562 Theft Other 2014-06-30 "The covered entity's (CE's) business associate (BA) mailed a package to the CE that was supposed to contain a backup data tape and compact disc containing protected health information (PHI); however, the tape was not in the package when delivered. Approximately 2,000 individuals were affected by the breach. The PHI included demographic, financial, and clinical information. The CE provided breach notification to affected individuals, HHS, and the media. Following the breach, the CE revised its procedures for back up data storage instead of sending tapes via the mail. Following OCR's investigation, the CE continued to reevaluate ways to enhance administrative, physical, and technical safeguards. + +" 2009-12-09 +Goodwill Industries of Greater Grand Rapids, Inc. MI 10000 Theft Other 2014-01-23 "On December 15, 2009, a safe was stolen from Goodwill's off-site facility, which contained five unencrypted back-up tapes. The breach affected approximately 10,000 individuals. The protected health information involved in the breach included full names, addresses, dates of birth, reasons for referral, dates of service, miscellaneous demographics, and, in some cases, Social Security numbers. The covered entity moved the off-site storage of back-up tapes to a new site controlled by Goodwill. The tapes are now kept in a commercial grade safe with a combination lock. The actions taken by Goodwill prior to OCR's formal investigation brought the covered entity into compliance. + +" 2009-12-15 +Children's Medical Center of Dallas TX 3800 Loss Other Portable Electronic Device, Other 2014-01-23 2009-11-19 +Concentra TX 900 Theft Laptop 2014-01-23 2009-11-19 +Ashley and Gray DDS MO 9309 Theft Desktop Computer 2014-01-23 2010-01-10 +Advocate Health Care IL 812 Theft Laptop 2014-01-23 "On November 24, 2009, an Advocate nurse's laptop computer was stolen. The missing laptop computer contained the protected health information of approximately 812 individuals. The protected health information involved in the breach included name, address, dates of birth, social security numbers, insurance information, medication, and diagnoses. Following the breach, Advocate specifically addressed mobile device security and accepted use. Additionally, OCR's investigation resulted in Advocate workforce members that use mobile devices are now required to fill out and submit an acknowledgment form that establish proper administrative, technical, and physical security safeguards. + +" 2009-11-24 +The Methodist Hospital TX 689 Theft Other 2014-01-23 "An unencrypted laptop computer was stolen from the covered entity's unlocked testing office. The laptop computer contained the protected health information of approximately 689 individuals. The protected health information involved in the breach included names, dates of birth, Social Security numbers, and the age, gender, race, and medication information of affected individuals. Following the breach, the covered entity restricted the storage of electronic protected health information to network drives. Additionally, OCR's investigation resulted in the covered entity improving their physical safeguards and in retraining employees. + +" 2010-01-18 +University of California, San Francisco CA 7300 Theft Laptop 2014-01-23 2009-11-30 +Carle Clinic Association IL 1300 Theft Other, Paper 2014-01-23 2010-01-13 +Educators Mutual Insurance Association of Utah UT Health Behavior Innovations (HBI) 5700 Theft Other 2014-01-23 2009-12-27 +University Medical Center of Southern Nevada NV 5103 Theft Paper 2014-01-23 "Between the dates of July 31, 2009 and November 19, 2009, a former UMC volunteer faxed patient face sheets to an attorney who used the sheets to contact prospective clients. Although UMC only had proof of two disclosures, it chose to notify all 5,301 individuals that could have been affected by the breach. The protected health information involved in the breach included names, addresses, dates of birth, social security numbers, and diagnoses. Following the breach, UMC conducted an internal investigation, notified all 5,301 individuals, notified the media, and notified the Secretary. Additionally, UMC reformulated face sheets so that they no longer include full social security numbers and provided all possible affected individuals with a year of free credit monitoring. As a result of this breach, at least one person has been indicted on one count of conspiracy to illegally disclose personal health information in violation of the HIPAA + +" 2009-10-31 +Center for Neurosciences AZ 1100 Theft Laptop 2014-01-23 2009-12-15 +Brown University RI Blue Cross Blue Shield of RI 528 Other Paper 2014-01-23 "On January 5, 2010, BCBSRI was notified that a 16 page report pertaining to Brown University's health plan was impermissibly disclosed to two other BCBSRI agents. The reports contained the PHI of approximately 528 individuals. The PHI involved: first and last names, dates of service, cost of medical care provided, and member identification numbers. Following the breach, BCBSRI recovered the reports, received written assurances that any electronic copies of the reports were deleted, notified affected individuals of the breach, implemented new procedure for all outgoing correspondence, and is in the process of auditing all affected members' claim history to ensure no fraud. + +" 2009-12-11 +MMM Heath Care Inc. PR MSO of Puerto Rico, Inc. 1907 Theft Paper 2014-06-03 "The covered entity's (CE) business associate (BA) erroneously merged two lists which led to the disclosure of protected health information (PHI) of 1,907 individuals. The PHI included names, internal identification numbers, and the number of emergency room visits. Upon discovery of the breach, the CE's BA established a quality control process in order to ensure adequate safeguards for that letters that are sent by mail. As a result of OCR's investigation, the CE created and implemented additional policies and procedures for quality control of mailings. The CE also provided training to all staff on its revised privacy and security policies and procedures. + + + + + +" 2010-02-04 +PMC Medicare Choice PR MSO of Puerto Rico 605 Theft Paper 2014-06-03 "The covered entity's (CE) business associate (BA) erroneously merged two lists which led to the disclosure of protected health information (PHI) of 605 individuals. The PHI included names, internal identification numbers, and the number of emergency room visits. Upon discovery of the breach, the CE's BA established a quality control process in order to ensure adequate safeguards for that letters that are sent by mail. As a result of OCR's investigation, the CE created and implemented additional policies and procedures for quality control of mailings. The CE also provided training to all staff on its revised privacy and security policies and procedures. + + + +" 2010-02-04 +Cardiology Consultants/Baptist Health Care Corporation FL 8000 Theft Desktop Computer 2014-06-30 "A desktop computer that contained the e-PHI of approximately 8,000 individuals was stolen from the covered entity's (CE) locked medical suite. The PHI involved in the breach included names, dates of birth, medical record numbers, ultrasound information, exam dates, and reasons for the ultrasound. The computer that was stolen used proprietary software and a special electronic key to access the PHI. The CE provided breach notification to affected individuals, HHS, and the media and posted substitute notification on its website. Following the breach, the CE worked with law enforcement to identify the possible suspect. The CE upgraded its facility access controls to include proximity card readers for every location that stores PHI. As a result of OCR's investigation the CE updated its risk analysis and carried out additional risk management activities. + + + +" 2009-12-19 +State of TN, Bureau of TennCare TN 3900 Theft Paper 2014-06-24 "The covered entity (CE) mailed the wrong information to 3,900 individuals based on a corrupted data file it received from a state agency. The types of PHI involved were names, dates of birth, social security numbers, member identification numbers, and in some cases, diagnoses, treatments, conditions, and medications. Following the breach, the CE immediately fixed the corrupted file and mailed corrected letters. The CE provided breach notification to HHS, the media, and affected individuals and provided substitute notification by posting on its website. It also offered affected individuals one year of free credit monitoring and comprehensive credit services. The CE also worked with the state agency to implement a new procedure to improve safeguards for PHI. OCR obtained assurances that the CE implemented the corrective action listed above. + + + +" 2009-12-23 +Lucille Packard Children's Hospital CA 532 Other Desktop Computer 2014-01-23 2010-01-11 +University of New Mexico Health Sciences Center NM 1900 Other Desktop Computer 2014-01-23 2010-02-08 +Advanced NeuroSpinal Care CA 3500 Theft Network Server 2014-04-22 A computer containing the electronic protected health information (ePHI) of 3,500 individuals was stolen from the office of a covered entity (CE). The ePHI included patient names, addresses, dates of birth, social security numbers, driver's licenses, claims information, diagnoses, and conditions. As a result of the loss, the CE upgraded the alarm system and replaced the server housing and storage security lock-up. The CE also notified affected individuals, the media, appropriate government agencies, and law enforcement. In addition, the CE established an office-based hotline to assist affected individuals. As a result of OCR's investigation, the CE has implemented regularly scheduled security risk analyses and has installed window bars, roll down shutters, four video surveillance cameras, and other physical security measures to prevent theft. 2009-12-30 +Aspen Dental Care P.C. CO 2500 Theft Other 2014-06-30 "A computer hard drive containing encrypted patient records was stolen from the covered entity's (CE) safe. The hard drive contained clinical and demographic information of approximately 2,500 patients. Following the breach, the CE provided additional training to its staff. OCR obtained assurances that the CE implemented the corrective action listed above. + + + +" 2009-10-04 +Shands at UF FL 12580 Theft Laptop 2014-01-23 "A laptop containing certain information collected on approximately 12,580 individuals referred to Shands at UF GI Clinical Services was stolen from the private residence of an employee. The stolen information included patient names, social security numbers, and medical record numbers. As a result of the incident, the employee was counseled by her supervisor, issued written corrective action with a 3-day suspension, and provided additional HIPAA training. OCR reviewed Shands at UF's most recent Risk Analysis and Risk Management Plans and they revealed no high risk findings related to encryption, workstation use, or physical security. OCR's investigation found that Shands at UF has implemented appropriate technical safeguards, such as secure VPN network connections and network storage for workforce usage, encrypted USB portable flash drives, and PGP whole disk encryption. + +" 2010-01-27 +Wyoming Department of Health WY 9023 Unauthorized Access/Disclosure Network Server 2014-01-23 2009-12-02 +Thrivent Financial for Lutherans WI 9500 Theft Laptop 2014-01-23 "On January 29, 2010, there was a break-in at one of the Thrivent's offices and five laptop computers were stolen; four of the five laptops were recovered. The missing laptop computer contained the protected health information of approximately 9,400 individuals. The protected health information involved in the breach included name, address, date of birth, social security number, prescription drugs, medical condition, age, weight, etc. Thrivent provided OCR with additional controls to remedy causes of security breach at various stages of implementation. The actions taken by the CE prior to OCR's formal investigation brought the CE into compliance. + +" 2010-01-29 +North Carolina Baptist Hospital NC 554 Theft Paper 2014-01-23 2010-02-15 +Montefiore Medical Center NY 625 Theft Laptop 2014-06-03 An unencrypted laptop computer containing the electronic protected health information (ePHI) of 625 individuals was stolen from the covered entity's (CE) mobile dental van. The ePHI included names, dates of birth, medical record numbers and dental x-rays. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media and affected individuals. As a result of OCR's investigation, the CE revised its procedures so that all ePHI is stored in a data center, rather than the mobile dental van laptop. In addition, the CE encrypted all mobile dental van laptops and improved physical security for the van. The CE developed a new policy on ePHI security and retrained all staff. OCR obtained assurances that the CE implemented the corrective action listed above. 2010-02-20 +Ernest T. Bice, Jr. DDS, P.A. TX 21000 Theft Other Portable Electronic Device, Other 2014-01-23 "Three unencrypted external back-up drives were stolen from a safe in the covered entity's locked office. The laptop computer contained the protected health information of approximately 21,000 individuals. The protected health information involved in the breach included names, addresses phone numbers, dates of birth, social security numbers, insurance information, and treatment histories. Following the breach, the covered entity moved back-up data offsite and encrypted all workstations. Additionally, OCR's investigation resulted in the covered entity improving their physical safeguards and in retraining employees. + +" 2010-02-20 +Lee Memorial Health System FL 3800 Other Paper 2014-01-23 "The covered entity sent postcards to approximately 3,800 patients, which listed the patients' demographic information, and a statement that read, 'Your Physician Has Moved,' with a name and description of the practice, Infectious Disease Specialist. The types of PHI involved were demographic and clinical information. Voluntary actions taken prior to OCR's investigation include the issuance of sanctions and review of policies and procedures. + +" 2010-01-29 +Laboratory Corporation of America/Dynacare Northwest, Inc. WA 5080 Theft Laptop 2014-01-23 "A laptop computer was stolen from a workforce member's car. The laptop computer contained the protected health information of approximately 5080 individuals. The protected health information involved in the breach included names, addresses, dates of birth, Social Security numbers, and lab results. Following the breach, the covered entity encrypted all laptop computers. + +" 2010-02-12 +Mount Sinai Medical Center FL 2600 Theft Laptop 2014-01-23 2010-03-09 +Griffin Hospital CT 957 Hacking/IT Incident Network Server 2014-01-23 2010-02-04 +Hypertension, Nephrology, Dialysis and Transplantation, PC AL 2465 Theft Laptop 2014-01-23 2010-03-06 +Reliant Rehabilitation Hospital North Houston TX Computer Program and Systems, Inc. (CPSI) 768 Unauthorized Access/Disclosure E-mail 2014-01-23 2010-02-09 +Laboratory Corporation of America / US LABS / Dianon Systems, Inc AZ 2773 Theft Other Portable Electronic Device 2014-01-23 2010-02-18 +University of Pittsburgh Student Health Center PA 8000 Theft, Loss Paper 2014-01-23 2010-03-11 +Providence Hospital MI 83945 Other Other 2014-01-23 2010-02-04 +VHS Genesis Lab Inc. IL 6800 Loss Paper 2014-01-23 2010-01-10 +John Muir Physician Network CA 5450 Theft Laptop 2014-01-23 2010-02-04 +Beatrice Community Hospital and Health Center NE McKesson Information Solutions, LLC 660 Other Paper 2014-01-23 2010-03-19 +Pediatric Sports and Spine Associates TX 955 Theft Laptop 2014-01-23 "An unencrypted laptop was stolen from an employee's vehicle. The laptop contained the protected health information of approximately 955 individuals. The protected health information involved in the breach included names, addresses, dates of birth, social security numbers, diagnoses, medications and other treatment information. Following the discovery of the breach, the covered entity revised policies, retrained staff and implemented additional physical and technical safeguards including encryption software. The covered entity also removed the stolen laptop's access to the server, sanctioned the involved employee, notified the affected individuals and notified the local media. + +" 2010-02-10 +Affinity Health Plan, Inc. NY 344579 Theft Other 2014-05-28 2009-11-24 +Tomah Memorial Hospital WI 600 Other Other 2014-01-23 2010-03-19 +Praxair Healthcare Services, Inc. (Home Care Supply in NY) CT 54165 Theft Laptop 2014-01-23 "A laptop computer was stolen from the covered entity's office by a former employee after it had been damaged. The laptop computer contained the PHI of approximately 54,165 individuals. The computer contained a limited amount of PHI, including client names and one or more of the following: addresses, phone numbers, social security numbers, insurance provider names and policy numbers, medical diagnostic codes or medical equipment. Following the breach, the covered entity notified all affected individuals, the media, and HHS of the breach. Additionally, the covered entity completed its laptop encryption project to cover all PHI stored on computers in the office. Additionally, OCR's investigation resulted in the covered entity reinforcing the requirements of HIPAA to its employees. + +" 2010-02-18 +Massachusetts Eye and Ear Infirmary MA 3594 Theft Laptop 2014-01-23 2010-02-19 +Blue Cross & Blue Shield of Rhode Island RI 12000 Theft Paper 2014-06-30 "A covered entity (CE) donated a file cabinet containing the protected health information (PHI) of 12,000 individuals before cleaning it out. The PHI included members' names, addresses, telephone numbers, social security numbers, and Medicare identification numbers. The covered entity (CE) provided breach notification to HHS, the affected individuals, and media, and offered all affected individuals free credit monitoring for a period of one year. Following the breach, the CE sanctioned the employees involved in the incident and held a mandatory training regarding the HIPAA Privacy and Security Rule for all departments involved in the breach. The CE also revised the policy for office moves. OCR obtained assurances that the CE implemented the corrective action listed above. + + + +" 2009-12-20 +South Carolina Department of Health and Environmental Control SC 2850 Improper Disposal Paper 2014-01-23 2010-02-17 +St. Joseph Heritage Healthcare CA 22012 Theft Desktop Computer 2014-01-23 "22 computers were stolen from Clinical Management Service office.Five of the stolen computers contained the protected health information of approximately 22,012 individuals. The protected health information involved in the breach included name, date of birth, social security number, referral number, encounter number, facility, member ID, diagnosis, procedure, and/or diagnosis code. As a result of this incident, St. Joseph notified the potentially affected individuals, notified the local media, installed security cameras, re-trained employees, and installed encryption software on all laptops and Computers enterprise-wide. OCR's investigation resulted in the covered entity improving their physical and technological safeguards and retraining employees. + +" 2010-03-06 +Medical Center At Bowling Green KY 5148 Theft Other Portable Electronic Device, Other 2014-01-23 2010-03-24 +GENERAL AGENCIES WELFARE BENEFITS PROGRAM TN TOWERS WATSON 1874 Loss Other 2014-01-23 2010-02-05 +UnitedHealth Group health plan single affiliated covered entity MN 735 Theft Other, Paper 2014-01-23 2010-03-02 +South Texas Veterans Health Care System TX 1430 Loss, Improper Disposal Paper 2014-01-23 2009-09-30 +Rockbridge Area Community Services VA 500 Theft Laptop, Desktop Computer 2014-01-23 2010-03-12 +Emergency Healthcare Physicians, Ltd. IL Millennium Medical Management Resources, Inc. 180111 Theft Other Portable Electronic Device, Other 2014-01-23 2010-02-27 +VA Eastern Colorado Health Care System CO 649 Theft Paper 2014-06-19 A covered entity's (CE's) employee placed paper records containing protected health information (PHI) in an unsecured box that was left undiscovered in a public parking garage for four days. The box contained the PHI of 649 patients. The PHI included treatment records, productivity reports, coding information, names, medical treatments, conditions, diagnoses, and social security numbers. Upon discovery of the breach, the CE notified the affected individuals and provided credit protection to those whose social security numbers had been breached. The CE provided OCR with copies of its breach prevention policies and procedures. Following OCR's investigation, the employee who left the records resigned from her position and the CE improved its breach response procedures. 2010-01-19 +Miami VA Healthcare System FL 568 Loss Paper 2014-01-23 2010-01-19 +Heriberto Rodriguez-Ayala, M.D. TX 4200 Theft Laptop 2014-01-23 2010-04-03 +Georgetown University Hospital DC 2416 Theft, Other E-mail, Other Portable Electronic Device 2014-01-23 "An employee of the covered entity emailed protected health information (PHI) to an offsite research office (which is not itself a covered entity) in violation of the review preparatory to research protocol. The research office stored the electronic information on an external hard drive that was later stolen. The device contained the PHI of 2,416 individuals. The PHI involved in the breach included names, dates of birth, and clinical information. In response to this incident, the covered entity terminated transmission of the PHI to this research office and gave the responsible employee a verbal warning and counseling. Additionally, the covered entity undertook a review of all research affiliations involving PHI of hospital patients to confirm that appropriate documentation and procedures are in place. + +" 2010-03-26 +Silicon Valley Eyecare Optometry and Contact Lenses CA 40000 Theft Network Server 2014-01-23 2010-04-02 +Loma Linda University Health Care CA 584 Theft Desktop Computer 2014-01-23 2010-04-04 +Veterans Health Administration DC Heritage Health Solutions 656 Theft Laptop 2014-01-23 2010-04-22 +State of New Mexico Human Services Department, Medical Assistance Division NM DentaQuest 9600 Theft Laptop 2014-01-23 2010-03-20 +Oconee Physician Practices SC 653 Theft Laptop 2014-01-23 2010-05-09 +University of Rochester Medical Center and Affiliates NY 2628 Other Paper 2014-01-23 2010-04-19 +Omaha Construction Industry Health and Welfare Plan NE DeBoer & Associates 800 Theft Laptop 2014-01-23 2009-01-11 +City of Charlotte, NC (Health Plan) NC 5220 Loss Other 2014-01-23 2010-02-03 +VA North Texas Health Care System TX 4083 Improper Disposal Paper 2014-01-23 2010-05-04 +Rainbow Hospice and Palliative Care IL 1000 Theft Laptop 2014-01-23 "An employee's laptop was stolen out of her bag while she was making an admission visit in a patient's home. The evidence showed that although the covered entity had a policy of encrypting and password-protecting its computers, this particular computer did not require a password most of the time. The invoices contained the protected health information (PHI) of approximately 1,000 individuals. The PHI stored on the laptop included names, addresses, dates of birth, phone numbers, Social Security numbers, Medicare numbers, electronic health records and commercial insurance information. Following the breach, the covered entity notified its clients of the incident, placed notice on its website and in The Daily Herald, sanctioned the employee for changing the security settings on the laptop in question, and established stringent computer security guidelines, and retrained its staff in the new requirements, with the intention of preventing a similar event from occurring again. + +" 2010-04-12 +Cincinnati Childrens Hospital Medical Center OH 60998 Theft Laptop 2014-01-23 2010-03-27 +Occupational Health Partners KS 1105 Theft Laptop 2014-01-23 2010-05-12 +AvMed, Inc. FL 1220000 Theft Laptop 2014-06-30 Two laptop computers with questionable encryption (each containing the electronic protected health information (ePHI) of 350,000 individuals) were stolen from the covered entity's (CE) premises. The types of ePHI involved included demographic and clinical information, diagnoses/conditions, medications, lab results, and other treatment data. After discovering the breach, the CE reported the theft to law enforcement and worked with the local police to recover the laptops. As a result of OCR's investigation, the CE developed and implemented new policies and procedures to comply with the Security Rule. The CE also provided breach notification to all affected individuals, HHS, and the media and placed an accounting of disclosures in the medical records of all affected individuals. 2009-12-10 +UnitedHealth Group health plan single affiliated covered entity MN 16291 Other Paper 2014-01-23 "Paper correspondence to certain members in UnitedHealth's prescription drug plans were in advertently sent to the incorrect temporary address due to a database administration error. Approximately 16,291 individuals were affected by the breach. UnitedHealth member's name, plan number and in some instances, date of birth and/or limited medical information. United Health reported that it stopped using PDI's proprietary database for address updates and made outbound verifications calls to members to get accurate temporary addresses. United Health reported that it revised its address update process. + +" 2010-01-26 +Lincoln Medical and Mental Health Center NY Siemens Medical Solutions, USA, Inc 130495 Theft Other 2014-06-19 The covered entity's business associate (BA), Siemens Medical Solutions USA, Inc., shipped seven unencrypted compact disks (CDs) that contained the electronic protected health information (ePHI) of 130,495 individuals to the covered entity (CE), Lincoln Medical and Mental Health Center. The CD's, containing back-up data, were lost in transit. The ePHI included names, addresses, social security numbers, medical record numbers, health plan information, dates of birth, dates of admission and discharge, diagnostic and procedural codes, and driver's license numbers. The CE provided breach notification to affected individuals, HHS, and the media. Upon discovery of the breach, the CE directed the BA to cease using the shipping service as a means of transporting the CDs. As a result of OCR's investigation, the BA adopted a procedure to encrypt CDs. The CE also implemented a procedure for a senior employee of the BA to physically deliver the encrypted CDs to the CE. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2010-03-24 +Nihal Saran, MD MI 2300 Theft Laptop 2014-01-23 "A password protected laptop computer containing protected health information (PHI) was stolen from Dr. Saran's personal residence. The laptop contained the PHI of approximately 2,300 individuals. The PHI stored on the laptop included patients' names, addresses, dates of birth, Social Security numbers, insurance information, and diagnoses. Following the breach, Dr. Saran notified the Northville Township Police Department of the theft, contacted the individuals reasonably believed to have been affected by the breach, sent a notice of the breach to the Detroit Free Press and the Monroe News, and installed encryption software for its billing software. + +" 2010-05-02 +University of Louisville Research Foundation, Inc., DBA The Kidney Disease Program KY 708 Hacking/IT Incident Network Server 2014-01-23 2008-10-01 +St. Jude Children's Research Hospital TN 1745 Loss Laptop 2014-01-23 2010-04-19 +TennCare TN DentaQuest 10515 Theft Laptop 2014-06-20 "A car containing an unencrypted laptop computer was stolen from West Monroe Partners, a contractor for the covered entity's (CE) business associate (BA), DentaQuest. The laptop stored a database containing the electronic protected health information (ePHI) of approximately 76,000 individuals, including data on 10,515 of the CE's members. The types of PHI involved in the breach included names, social security numbers, dates, and certain provider identification numbers. The CE and BA worked together to provide breach notification to affected individuals and the media, and offered free credit monitoring and enhanced credit services to affected individuals for one year. The CE reported the breach to HHS and provided substitute notification on its website. The BA implemented procedures to ensure that any third party laptops connecting to its network employ disk encryption. Further, the BA established a policy to prohibit contractors from storing PHI on laptops. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2010-03-20 +The Children's Medical Center of Dayton OH 1001 Other E-mail 2014-01-23 2010-04-22 +Comprehensive Care Management Corporation NY 1020 Theft Laptop, Desktop Computer, Network Server, E-mail 2014-06-19 OCR opened an investigation of the covered entity (CE), Comprehensive Care Management Corporation, after it reported two former employees sent emails that contained the electronic protected health information (ePHI) of 1,020 individuals to their personal email accounts to open a competitor organization. The ePHI included names, addresses, and enrollment information. Upon discovery of the breach, the CE conducted an internal inquiry and found that the former employees disclosed the ePHI to its competitor. As a result of OCR's investigation, the CE replaced and strengthened external firewalls, restricted access to email websites, restricted the use of portable devices, limited the ability to upload data to external websites, and evaluated new monitor and control software for network information. In addition, the CE provided training to all staff on its HIPAA policies and procedures. The CE also entered into an agreement with its competitor who hired the former employees to return or destroy the ePHI. 2010-04-30 +alma aguado md pa TX 600 Theft Network Server 2014-04-23 OCR investigated the covered entity (CE) following a report that its main server and desktop computers containing the electronic protected health information (ePHI) of 600 individuals were taken from the CE's office. The ePHI involved in the breach included patient names, addresses, dates of birth, and social security numbers. As a result of OCR's investigation, the CE changed its privacy and security policies, retrained its employees and provided additional physical security to better safeguard patient ePHI. 2010-05-29 +University Hospital GA Augusta Data Storage, Inc 14000 Loss Other 2014-01-23 2010-05-07 +University Health System NV 7526 Theft Network Server 2014-01-23 2010-06-11 +Sinai Hospital of Baltimore, Inc. MD Aramark Healthcare Support Services, LLC 937 Other E-mail 2014-01-23 "A business associate employee sent an email to multiple patients without concealing patient email addresses. The message concerned a dietary program in which the names and email addresses were visible to all recipients. The breach affected 937 individuals. In response to this incident, the covered entity took steps to enforce the requirements of its business associate agreement with Aramark. The business associate counseled the employee responsible for the breach and retrained all employees who may communicate with patients via email on the requirements of the Privacy and Security Rules as well as related policies and procedures. + +" 2010-05-03 +Mary M. Desch,MD/PathHealer, LTD AZ 5893 Theft Laptop 2014-01-23 2010-05-15 +Children's Hospital & Research Center at Oakland CA 1000 Other Paper 2014-01-23 2010-05-25 +Centerstone TN 1537 Other Desktop Computer, Paper 2014-01-23 2010-05-01 +California Department of Healthcare Services CA Care 1st Health Plan 29000 Loss, Other Other Portable Electronic Device, Other 2014-01-23 2010-04-29 +Long Island Consultation Center NY 800 Theft Other Portable Electronic Device, Other 2014-06-19 The covered entity (CE), Long Island Consultation Center, misplaced an unencrypted portable device that contained the electronic protected health information (ePHI) of 800 individuals. The ePHI included names, dates of birth, diagnoses, and other treatment information. Upon discovery of the breach, the CE conducted a search for the portable device. The CE provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE improved physical security. The CE also developed and implemented a policy and procedure prohibiting use of portable media for storing ePHI and trained staff on its new policy. 2010-05-21 +NYU Hospitals Center NY 2563 Theft Other Portable Electronic Device 2014-05-28 The covered entity (CE) misplaced an unencrypted USB drive that contained the electronic protected health information (ePHI) of 2,563 individuals. The ePHI included names, medical record numbers, ages, genders, procedures, attending physicians' names, anesthesiologists' names, types of anesthesia, times of arrival in the recovery room, and times of discharge. Upon discovery of the breach, the CE reported the incident to internal security as a possible theft and conducted a thorough search of the perimeter. The CE provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE stopped using USB drives and local desktop computers for data storage. In addition, the CE updated physical security in the recovery room and installed data prevention software to monitor, block or encrypt mobile media used in the CE. Further, the CE purchased encrypted USB drives for workforce members with an identified need to download and store ePHI. The CE also revised its mobile device and portable storage media policy and retrained all workforce members on its policies. 2010-05-08 +University of Florida FL 2047 Other Paper 2014-01-23 2010-05-24 +SunBridge Healthcare Corporation NM 3830 Theft Laptop 2014-01-23 2010-05-11 +Department of Health Care Policy & Financing CO Governor's Office of Information Technology 105470 Theft Desktop Computer 2014-01-23 2010-05-17 +Prince William County Community Services (CS) VA 669 Theft Other Portable Electronic Device 2014-01-23 2010-06-18 +E. Brooks Wilkins Family Medicine, PA NC 13000 Theft Desktop Computer, Other 2014-01-23 "The breach report indicated that former employees took protected health information (PHI) pertaining to 13,000 patients and disclosed it to a competing medical practice. The PHI included the names and contact information for the patients. Following the breach, the entity terminated the employees who impermissibly used and disclosed the PHI. OCR also confirmed that the entity complied with the provisions of the Breach Notification Rule and notified the affected individuals. Additionally, the entity retrained its staff regarding the policies and procedures for safeguarding of PHI. + +" 2010-02-01 +John Deere Health Benefit Plan for Wage Employees IL UnitedHealthcare Insurance Company 1097 Other Paper 2014-01-23 2010-06-24 +South Shore Hospital MA Iron Mountain Data Products, Inc. (now known as 800000 Loss Other Portable Electronic Device, Other, Electronic Medical Record 2014-01-23 2010-02-26 +Montefiore Medical Center NY 16820 Theft Desktop Computer 2014-06-19 Two unencrypted desktop computers containing the electronic protected health information (ePHI) of 16,820 individuals were stolen from the covered entity (CE). The ePHI included medical record numbers, dates of birth, admission /discharge dates, billing codes, and social security numbers. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media, and affected individuals. It also provide substitute notification by posting on its website. As a result of OCR's investigation, the CE replaced its building alarm and installed bars on the windows. In addition, the CE directed its staff to save patient data only on a centralized network drive, moved all ePHI stored on desktop hard drives to centralized secured network servers, and encrypted all of its computers. The CE also revised its policy and procedure on password management and provided training to all staff on its new policy. 2010-05-22 +DC Chartered Health Plan, Inc DC 540 Theft Laptop 2014-01-23 2010-05-26 +Montefiore Medical Center NY 23753 Theft Desktop Computer 2014-06-19 OCR opened an investigation of the covered entity (CE), Montefiore Medical Center, after it reported three unencrypted desktop computers were stolen that contained the electronic protected health information (ePHI) of 23,753 individuals. The ePHI included names, medical record numbers, dates of birth, parent or guardian contact numbers, asthma diagnoses, vaccination information, and number of visits to the school health clinic. Upon discovery of the breach, the CE filed a police report and provided breach notification to affected individuals, HHS, and the media. As a result of OCR's investigation, the CE updated its building alarm to include additional motion sensors and installed surveillance cameras. Further, the CE encrypted all of its computers, advised that no ePHI is stored on desktop hard drives, removed all ePHI from its computers, and stored ePHI on the centralized secured network servers. The CE also revised its policy and procedure on password management and provided training to all staff on its new policy. 2010-06-09 +Medina County OB/GYN OH 1200 Improper Disposal Paper 2014-01-23 2010-06-13 +The University of Texas at Arlington TX 27000 Hacking/IT Incident Network Server 2014-01-23 "A file server at the Office of Health Services was compromised and impermissibly accessed. The compromise potentially exposed the prescription records of 27,000 individuals to an unauthorized source. The protected health information involved in the breach included names, addresses diagnostic codes, name of medication prescribed, medication costs and some social security numbers. Following the discovery of the breach, UTA removed the server from the network, notified the affected individuals and notified local media. Following the breach, the covered entity also replaced the operating system and implemented additional technical safeguards. + +" 2009-02-19 +Aetna CT 6372 Improper Disposal Paper 2014-01-23 2010-03-29 +Charles Mitchell MD TX 6873 Theft Desktop Computer 2014-06-30 A burglary occurred at the covered entity's (CE) facility and two desktop computers containing protected health information (PHI) were stolen. Approximately 6873 individuals were affected. The PHI involved included names, addresses, dates of birth, social security numbers, diagnoses and conditions, medications, and other treatment information. OCR closed this investigation after determining that the individual who reported the breach worked for a CE no longer in existence. 2010-06-27 +Humana Inc [case 4486] KY Matrix Imaging 2631 Other Paper 2014-01-23 2010-06-25 +WellPoint, Inc. IN 31700 Hacking/IT Incident Network Server 2014-01-23 2009-11-03 +Carolina Center for Development and Rehabilitation NC 1590 Theft Paper 2014-06-30 The covered entity's (CE) staff inadvertently sent twenty-three boxes containing the protected health information (PHI) of 1,590 patients to a recycling center. The PHI included patients' full names, addresses, dates of birth, social security numbers, insurance identification numbers, driver's license numbers, diagnoses, medication information, checking and savings account numbers, credit and debit card numbers, and photographs of the patients. Following the breach, the CE immediately took steps for the records to be returned. The CE notified HHS, the media, and all individuals affected by the breach, and established a toll free number for patients to call for more information. The CE cooperated with the state attorney general's investigation and suspended the responsible staff members. Following OCR's investigation, the CE placed a record into its accounting of disclosure log for each individual affected and terminated the employment of the staff involved in the breach. In addition, the CE revised its policies and procedures regarding the rights of individuals and safeguards for PHI, and re-trained staff. 2010-06-24 +Trinity Health Corporation Welfare Benefit Plan MI Mercer 1073 Loss Other 2014-01-23 2010-03-29 +Texas Children's Hospital TX 694 Theft Laptop 2014-01-23 2010-05-13 +Baylor College of Medicine TX 1646 Theft Laptop 2014-04-24 An unencrypted laptop containing electronic protected health information (ePHI) of approximately 1,618 individuals was stolen from the covered entity's (CE) affiliate. The ePHI involved in the breach included names, medical reconciliation numbers, dates of service, diagnoses, and dates of birth. Upon discovery of the breach, the CE and its affiliate jointly notified the affected individuals, OCR, and the local media. Notifications were delayed at the request of law enforcement. Following OCR's investigation, the CE revised policies and procedures to require encryption of all mobile devices containing PHI and began encrypting all necessary devices in order to ensure reasonable safeguards. 2010-05-13 +Wright State Physicians OH 1309 Other Laptop 2014-01-23 "On June 11, 2010, a laptop computer containing PHI was mistakenly discarded in the trash. The laptop computer contained the protected health information of approximately 1,309 individuals. The protected health information involved in the breach included patient full names or first initial and last name, dates of service, and in some cases, a brief description of medical condition or care. Following the breach, the covered entity submitted evidence of its progress in implementing encryption on its laptop computers in its various departments. + +" 2010-06-11 +Penn Treaty Network America Insurance Company PA 560 Other Other 2014-01-23 "Social security numbers were inadvertently printed on the address labels in a newsletter mailing. The mailing had 560 recipients. The covered entity acted to mitigate the disclosure by verifying that the all mail was correctly delivered. It also counseled the responsible employee and updated its policies and procedures. + +" 2010-06-04 +Aultman Hospital OH 13867 Theft Laptop 2014-01-23 2010-06-07 +Fort Worth Allergy and Asthma Associates TX 25000 Theft Network Server 2014-01-23 2010-06-29 +Beauty Dental, Inc. IL 657 Theft, Loss Paper 2014-01-23 "Following the breach, the covered entity notified its clients by letter of the incident, submitted a press release that outlined the circumstances of the breach to the Chicago Tribune and the Chicago Sun Times, required the individual who allegedly stole the documents to return all physical patient PHI in her possession and sign a statement swearing that she no longer possessed any patient documents, would not use or disclose the PHI in any manner and would erase an excel spreadsheet she had in her possession, installed a new security system for the office that requires the input of a code specific to each employee, and implemented new technical safeguards that limited employee access to ePHI according to the employee's position and rank. + +" 2010-06-05 +Walsh Pharmacy MA McKesson Pharmacy Systems LLC 11440 Other Other Portable Electronic Device, Other 2014-01-23 2010-06-03 +Jewish Hospital KY 2089 Theft Laptop 2014-01-23 2010-07-16 +St. John's Mercy Medical Group MO 1907 Improper Disposal Paper 2014-01-23 "Covered entity improperly disposed of patients' Protected Health Information (PHI), by placing the PHI in a dumpster outside of a doctor's office. The PHI involved in the breach included demographic, financial, clinical, and other medical information. Following the breach, the covered entity notified all affected individuals of the breach, posted a notice about the incident on its website; attempted to retrieve and track all of the medical records that were inappropriately disposed of; offered all affected individuals identity theft protection; obtained a formal apology from and assumed direct office operations management of the physician involved; re-educated its workforce to reinforce policies relating to appropriate medical record protection and disposal requirements. + +" 2010-06-07 +Thomas Jefferson University Hospitals, Inc. PA 21000 Theft Laptop 2014-01-23 2010-06-14 +UNCG Speech and Hearing Center NC 2300 Hacking/IT Incident Desktop Computer 2014-01-23 1997-01-01 +Idaho Power Group Health Plan ID Mercer Health & Benefits 5500 Loss Other 2014-01-23 "Idaho Power Group Health Plan's business associate, Mercer Health and Benefits, lost a backup tape as it was being sent via FEDEX from Boise to Seattle. The backup tape contained information of about 375,000 individuals that Mercer serviced. The total affected at Idaho Power was about 5,500 current and former employees and their dependents. The protected health information involved included names, addresses, dates of birth, and social security numbers. Although Mercer concluded that the lost tape was configured so that even a sophisticated user would be unlikely to be able to access the data within, both Mercer and Idaho Power notified all possible affected individuals and offered free credit protection services. To prevent a similar breach from occurring in the future, Mercer now stores backup tapes through a third party vendor who offers secure transport services. Mercer's Boise office now encrypts backup tapes. Following the incident, Idaho Power renegotiated its contract with Mercer and continues to evaluate its business relationship with Mercer. + +" 2010-03-29 +Loma Linda University School of Dentistry CA 10100 Theft Desktop Computer 2014-01-23 2010-06-13 +Ward A. Morris, DDS WA 2698 Theft Desktop Computer 2014-01-23 2010-07-16 +Chattanooga Family Practice Associates, P.C. TN 1711 Loss Other Portable Electronic Device, Other 2014-01-23 2010-07-15 +Yale University CT 1000 Theft Laptop 2014-01-23 2010-07-28 +University of Kentucky KY 2027 Theft Laptop 2014-01-23 2010-06-18 +Cook County Health & Hospitals System IL 7081 Theft Laptop 2014-01-23 "An employee's laptop was stolen out of a locked office; evidence shows that the laptop was password protected but not encrypted. The laptop contained the protected health information (PHI) of approximately 7,000 individuals. The PHI stored on the laptop included names, dates of birth, Social Security numbers, internal encounter numbers, and other administrative codes. Following the breach, the covered entity notified those individuals reasonably believed to have been affected by the breach, placed notice on its website and with a local news center; established stringent computer security guidelines, and retrained its staff in the new requirements with the intention of preventing a similar event from occurring again. + +" 2010-05-30 +Eastmoreland Surgical Clinic, William Graham, DO OR 4328 Theft Laptop, Desktop Computer, Other Portable Electronic Device, Other 2014-01-23 "Three desktop computers, one laptop computer, and a backup drive, containing the electronic protected health information (EPHI) of 4,328 individuals, were stolen on July 5, 2010. The EPHI involved in the breach included names, addresses, phone numbers, dates of birth, Social Security numbers, reason for visits, and insurance information. Following the breach, the covered entity implemented backup and whole disk encryption on electronic information systems that maintain EPHI and improved their physical safeguards. Additionally, OCR's investigation resulted in the covered entity improving their administrative safeguards, such as password complexity requirements and data backup protocols. + +" 2010-07-05 +SunBridge Healthcare Corporation NM 1000 Theft Other Portable Electronic Device, Other 2014-01-23 2010-06-26 +Holyoke Medical Center MA Pioneer Valley Pathology 24750 Improper Disposal Paper 2014-01-23 2010-07-26 +Newark Beth Israel Medical Center NJ KPMG LLP 956 Theft Other Portable Electronic Device, Other 2014-06-19 OCR opened an investigation of the covered entity (CE), Newark Beth Israel Medical Center, after it reported an employee of the CE's business associate (BA), KPMG LLP, lost an unencrypted USB drive that contained the electronic protected health information (ePHI) of 956 individuals. The ePHI included names and clinical information. Upon discovery of the breach, the CE's BA conducted a search of the area. The CE provided breach notification to HHS, the Media and affected individuals. As a result of OCR's investigation, the BA installed and implemented encryption software to its electronic equipment and devices. In addition, the BA encrypted and password protected all equipment and devices that could contain the CE's data. The BA also reprimanded and retrained the employee and retrained all employees on safeguarding ePHI. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2010-05-10 +Saint Barnabas Medical Center NJ KPMG LLP 3630 Theft Other Portable Electronic Device 2014-06-19 The covered entity (CE), Long Island Consultation Center, misplaced an unencrypted portable device that contained the electronic protected health information (ePHI) of 800 individuals. The ePHI included names, dates of birth, diagnoses, and other treatment information. Upon discovery of the breach, the CE conducted a search for the portable device. The CE provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE improved physical security. The CE also developed and implemented a policy and procedure prohibiting use of portable media for storing ePHI and trained staff on its new policy. 2010-05-10 +NYU School of Medicine--Aging and Dementia Clinical Research Center NY 1200 Loss Other Portable Electronic Device, Other 2014-01-23 2010-04-03 +University of Rochester Medical Center and Affiliates NY 857 Loss Other Portable Electronic Device 2014-01-23 2010-08-02 +State of Delaware Health Plan DE Aon Consulting 22642 Other Network Server 2014-01-23 "The business associate prepared a document as part of a request for proposal for the covered entity's vision benefit program which mistakenly included protected health information of 22,642 individuals. The document was posted online for five days. The protected health information involved in the breach included social security numbers, dates of birth, gender, zip codes, and vision plan enrollment information. In response to this incident, the covered entity implemented additional safeguards to prevent this type of impermissible disclosure of protected health information. In particular, the covered entity will now require several layers of review before allowing public disclosure of documents prepared by the business associate. The covered entity also took steps to enforce the requirements of its business associate agreement with Aon Consulting. Aon will provide affected individuals with free credit monitoring, fraud resolution resources, and identity theft insurance. Additionally, the business associate has provided assurances to the covered entity that it has taken steps to prevent this type of impermissible disclosure in the future. + +" 2010-08-16 +Curtis R. Bryan, M.D. VA 2739 Theft Laptop 2014-01-23 2010-07-12 +Mayo Clinic MN 1740 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2009-07-15 +LabCorp Patient Service Center NV 507 Theft Paper 2014-01-23 2010-08-02 +The Kent Center RI 1361 Theft Paper 2014-01-23 2010-07-13 +Pediatric and Adult Allergy, PC IA 19222 Loss Other Portable Electronic Device 2014-01-23 2010-07-11 +Ault Chiropractic Center IN 2000 Theft Laptop, Desktop Computer 2014-01-23 2010-09-15 +County of Los Angeles CA 33000 Theft Paper 2014-01-23 2010-07-29 +Matthew H. Conrad, M.D., P.A. KS 1200 Theft Laptop, Paper 2014-01-23 2010-08-20 +UnitedHealth Group health plan single affiliated covered entity MN CareCore National 1270 Other Paper 2014-01-23 2010-07-08 +Counseling and Psychotherapy of Throggs Neck NY 9000 Theft Desktop Computer 2014-01-23 2010-09-06 +United States Air Force OH 2123 Improper Disposal Paper 2014-01-23 2010-07-29 +State of Alaska, Department of Health and Social Services AK Alaskan AIDS Assistance Association 2000 Theft Other Portable Electronic Device, Other 2014-01-23 2010-09-07 +St. Vincent Hospital and Health Care Center, Inc. IN 1199 Theft Laptop 2014-01-23 2010-07-25 +Milford Regional Medical Center MA 20000 Improper Disposal Paper 2014-01-23 2010-07-26 +Alliance HealthCare Services, Inc. CA Oroville Hospital 1474 Theft Other Portable Electronic Device, Other 2014-04-24 "The covered entity (CE) filed a breach report with OCR after two USB storage devices containing electronic protected health information (ePHI) of 1,474 individuals were lost. The ePHI included names, dates of birth, and treatment information. Upon discovery of the breach, the CE notified individuals, OCR and the media. Additionally, the CE initiated an encryption project to encrypt emails, external hard drives, and related media. Following OCR's investigation, the CE filed a police report, updated its policies and procedures in an effort to better safeguard ePHI, and encrypted USB devices. + + + +" 2010-07-31 +Alliance HealthCare Services, Inc. CA Eden Medical Center 1474 Theft Other Portable Electronic Device, Other 2014-06-24 The covered entity (CE) lost two portable electronic storage devices containing the electronic protected health information (ePHI) of 1,474 individuals. The ePHI included patients' names, dates of birth, and treatment information. Upon discovery of the breach, the covered entity (CE) notified individuals, HHS, and the media. Additionally, the CE initiated a project to encrypt emails, external hard drives, and related electronic media. Following OCR's investigation, the CE filed a police report, updated its policies and procedures in order to better safeguard patients' ePHI, and encrypted portable electronic computer devices. 2010-08-05 +NewYork-Presbyterian Hospital and Columbia University Medical Center NY 6800 Theft Network Server 2014-06-19 "Data breach results in $4.8 million HIPAA settlements + +Two health care organizations have agreed to settle charges that they potentially violated the Health Insurance Portability and Accountability Act of 1996 (HIPAA) Privacy and Security Rules by failing to secure thousands of patients' electronic protected health information (ePHI) held on their network. The monetary payments of $4,800,000 include the largest HIPAA settlement to date. + +The U.S. Department of Health and Human Services (HHS) Office for Civil Rights (OCR) initiated its investigation of New York and Presbyterian Hospital (NYP) and Columbia University (CU) following their submission of a joint breach report, dated September 27, 2010, regarding the disclosure of the ePHI of 6,800 individuals, including patient status, vital signs, medications, and laboratory results. + +NYP and CU are separate covered entities that participate in a joint arrangement in which CU faculty members serve as attending physicians at NYP. The entities generally refer to their affiliation as 'New York Presbyterian Hospital/Columbia University Medical Center.' NYP and CU operate a shared data network and a shared network firewall that is administered by employees of both entities. The shared network links to NYP patient information systems containing ePHI. + +The investigation revealed that the breach was caused when a physician employed by CU who developed applications for both NYP and CU attempted to deactivate a personally-owned computer server on the network containing NYP patient ePHI. Because of a lack of technical safeguards, deactivation of the server resulted in ePHI being accessible on internet search engines. The entities learned of the breach after receiving a complaint by an individual who found the ePHI of the individual's deceased partner, a former patient of NYP, on the internet. + +In addition to the impermissible disclosure of ePHI on the internet, OCR's investigation found that neither NYP nor CU made efforts prior to the breach to assure that the server was secure and that it contained appropriate software protections. Moreover, OCR determined that neither entity had conducted an accurate and thorough risk analysis that identified all systems that access NYP ePHI. As a result, neither entity had developed an adequate risk management plan that addressed the potential threats and hazards to the security of ePHI. Lastly, NYP failed to implement appropriate policies and procedures for authorizing access to its databases and failed to comply with its own policies on information access management. + +'When entities participate in joint compliance arrangements, they share the burden of addressing the risks to protected health information,' said Christina Heide, Acting Deputy Director of Health Information Privacy for OCR. 'Our cases against NYP and CU should remind health care organizations of the need to make data security central to how they manage their information systems.' + +NYP has paid OCR a monetary settlement of $3,300,000 and CU $1,500,000, with both entities agreeing to a substantive corrective action plan, which includes undertaking a risk analysis, developing a risk management plan, revising policies and procedures, training staff, and providing progress reports. + +" 2010-07-01 +St. James Hospital and Health Centers IL 967 Improper Disposal Paper 2014-01-23 2010-08-10 +University of Oklahoma - Tulsa, Neurology Clinic OK 19200 Hacking/IT Incident Desktop Computer 2014-01-23 2010-07-28 +LORENZO BROWN, MD INC. CA 928 Theft Desktop Computer 2014-01-23 2010-08-17 +Milton Pathology Associates, P.C. MA Joseph A. Gagnon d/b/a Goldthwait Associates 11000 Improper Disposal Paper 2014-01-23 2010-07-26 +WESTMED Medical Group NY 578 Theft Laptop 2014-06-19 "An unencrypted laptop computer that contained the electronic protected health information (ePHI) of 578 individuals was stolen from the covered entity (CE), WestMed Medical Group. The ePHI included names, dates of birth and test results. Upon discovery of the breach, the CE filed a police report and provided breach notification to affected individuals, HHS and the media. As a result of OCR's investigation, the CE improved physical security by locking all laptops during the day and storing all laptops in a locked cabinet overnight. In addition, the CE reconfigured all laptops with strong passwords and implemented a new procedure to save data to a secure file server. Further, the CE encrypted all laptop hard drives. The CE also retrained staff on safeguarding ePHI. + + + +" 2010-08-17 +Debra C. Duffy, DDS TX 4700 Theft Laptop, Network Server 2014-01-23 "An unencrypted laptop and network server were stolen during a burglary of the office.The breach affected approximately 4700 individuals.The protected health information involved in the breach included treatment information for pediatric dental patients and social security numbers, insurance identification numbers and driver's license numbers. Following the discovery of the breach, the CE relocated the practice servers, secured the laptops and installed steel doors at the front entrance of the facility. Additionally, the CE notified the affected individuals and local media and retrained staff. + +" 2010-08-05 +Cumberland Gastroenterology, P.S.C. KY 2200 Theft Paper 2014-01-23 2010-09-18 +Johns Hopkins University Applied Physics Laboratory (JHU/APL) Medical and Dental Insurance Plan MD 692 Other Other 2014-01-23 "Protected health information was attached to an email addressed to 85 employees by a benefits staff member. Within 5 days, all recipients were notified, and the email was deleted. Approximately 692 individuals were affected by this breach. The email included names, dates of birth, social security numbers, and marital and disability status. To prevent a similar breach from happening in the future, the covered entity instituted a policy to encrypt emails containing protected health information before it is sent out from the benefits department. Following OCR's investigation, the covered entity updated its policies and procedures establishing a new business process to require that all emails sent by the benefits office to 5 or more staff members that includes an attachment be reviewed by another team member to ensure the proper document is attached and took personnel action with the responsible employee. Further, the benefits office will use an encryption specialist to train all benefits office staff in the proper methods of encryption, explore future capability of automated flagging of any electronic communications sent by benefits office staff containing potentially sensitive data such as 9-digit numbers, and obtain additional HIPAA training. + +" 2010-06-15 +LoneStar Audiology Group TX 585 Theft Laptop 2014-01-23 "A laptop was stolen from a workforce member's home. Approximately 585 individuals were affected. The PHI included addresses, dates of birth, diagnosis and conditions, medications and other treatment information. Following the breach, the covered entity encrypted all its laptops. After the initiation of OCR's investigation, the encryption of the laptops was completed. + +" 2010-08-11 +Utah Department of Health UT Utah Department of Workforce Services 1298 Other Desktop Computer, Paper 2014-01-23 2010-03-01 +SW Seattle Orthopaedic and Sports Medicine WA 9493 Hacking/IT Incident Network Server 2014-01-23 "A database web server, containing the electronic protected health information (EPHI) of 9,493 individuals, was breached by an unknown, external person(s) for use as a game server. Although there was no indication of access to EPHI, the EPHI on the database web server included names, dates of birth, types of x-rays, and dates of x-rays. Following the breach, the covered entity relocated two servers to its more secure primary data center and removed the Internet access line that resulted in the breach. Additionally, OCR's investigation resulted in the covered entity improving their administrative safeguards, such as incident response and reporting. + +" 2010-09-04 +University of Arkansas for Medical Sciences AR 1000 Theft Other Portable Electronic Device, Other 2014-01-23 2010-10-12 +BlueCross BlueShield of Tennessee, Inc. TN 1023209 Theft Other 2014-01-23 2009-10-02 +Northridge Hospital Medical Center CA 716 Loss Paper 2014-01-23 2010-10-16 +Puerto Rico Department of Health PR Triple-S Management, Corp.; Triple-S Salud, Inc.; 475000 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2008-10-03 +Aetna, Inc. CT 2345 Unauthorized Access/Disclosure Network Server 2014-01-23 "Aetna notified all possibly affected individuals of the breach, filed a breach report with OCR, commenced an investigation to identify and correct the root cause of the issue; the coding changes that were causing the breach were removed from IPS via Aetna's emergency Change Management procedures to prevent any further exposure while the problem was analyzed; once the specific code that conflicted with its proxy server settings was identified as the root cause of the breach, it was removed. Also, in an effort to mitigate any harm as a result of the breach, Aetna offered all affected individuals one year of free credit monitoring, and the notification letters included a toll-free number which was established specifically to answer questions related to this incident. + +" 2010-09-09 +Sta-home Health & Hospice MS 1104 Theft Desktop Computer 2014-01-23 2010-09-16 +Puerto Rico Department of Health PR Medical Card System/MCS-HMO/MCS Advantage/MCS Life 115000 Unauthorized Access/Disclosure Other Portable Electronic Device, Other 2014-01-23 2010-09-03 +VNA of Southeastern Ct. CT 12000 Theft Laptop 2014-01-23 2010-09-30 +Prime Home Care, LLC NE 1550 Theft Desktop Computer 2014-01-23 2010-09-13 +Visiting Nurse Service Association of Schenectady County NY 535 Theft Laptop 2014-06-19 An encrypted laptop computer that contained the electronic protected health information (ePHI) of 535 individuals was stolen from the covered entity (CE). The ePHI included names, addresses, and dates of birth. Upon discovery of the breach, the CE filed a police report to recover the stolen item. Following OCR's investigation, the CE disabled the involved staff member's account, verbally counseled the staff member, and retrained the staff member. The CE also adopted and implemented security policies and procedures for laptops/tablet devices and provided training to all staff. 2010-09-14 +Manor Care Indy (South), LLC. IN 845 Unauthorized Access/Disclosure Paper 2014-01-23 2010-09-11 +Robert Wheatley, DDS, PC MO 1400 Theft Laptop 2014-01-23 2010-10-17 +Henry Ford Hospital MI 3700 Theft Laptop 2014-01-23 2010-09-24 +Holy Cross Hospital FL 1500 Theft Paper 2014-01-23 2010-07-27 +Newark Beth Israel Medical Center NJ Professional Transcription Company, Inc. 1744 Theft Network Server 2014-06-19 The covered entity's (CE) business associate (BA), Professional Transcription Company, posted the electronic protected health information (ePHI) of 1,744 individuals on a website portal of the BA. The ePHI included names, dates of birth, diagnosis, and other clinical information. Upon discovery of the breach, the BA shut down the applicable server. The CE, Newark Beth Israel Medical Center, provided breach notification to HHS, the media, and affected individuals and also posted substitute notice on its website. As a result of OCR's investigation, the BA located the ePHI online and contacted Google to block files that contained ePHI. In addition, the BA retrained all employees regarding its security policies. The CE terminated its BA agreement with the BA. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2010-01-01 +Memorial Hospital of Gardena CA 771 Unauthorized Access/Disclosure Paper 2014-01-23 2010-10-14 +Oklahoma City VA Medical Center OK 1950 Theft, Loss, Improper Disposal Paper 2014-01-23 2010-10-08 +Albert Einstein Healthcare Network PA 613 Theft Desktop Computer 2014-01-23 2010-10-21 +Kings County Hospital Center NY 542 Theft Desktop Computer 2014-06-19 An unencrypted desktop computer that contained the electronic protected health information (ePHI) of 542 individuals was stolen from the covered entity (CE), Kings County Hospital Center. The ePHI included names, medical record numbers, admission and treatment dates, diagnostic treatment, pathology and/or medication information, telephone numbers and ages. Upon discovery of the breach, the CE filed a police report and provided breach notification to affected individuals, HHS, and the media. As a result of OCR's investigation, the CE installed an encryption system for all internal and external computers and laptops. The CE implemented a new policy that prohibits staff from storing ePHI on their local computer hard drives or Windows desktop. 2010-08-22 +University of Tennessee Medical Center TN 8200 Improper Disposal Paper 2014-01-23 2009-09-23 +Ochsner Health System LA H.E.L.P. Financial Corporation 9475 Unauthorized Access/Disclosure Paper 2014-01-23 "A programming error in a business associate's IT system caused the PHI of patients to be printed on letters sent to other patients. The printing error affected approximately 9475 individuals.The protected health information involved in the breach included patient names, medical record numbers and account balances. Following the discovery of the breach, the BA corrected the programming error and implemented additional quality checks. Additionally, the BA notified the affected individuals and the CE notified the local media. + +" 2010-09-27 +zarzamora family dental care TX 800 Theft Desktop Computer 2014-01-23 2010-10-15 +Hospital Auxilio Mutuo PR 1000 Theft, Unauthorized Access/Disclosure, Hacking/IT Incident Laptop, Desktop Computer 2014-01-23 2010-11-09 +Pinnacle Health System PA Gair Medical Transcription Services, Inc. 1085 Unauthorized Access/Disclosure Network Server 2014-01-23 "Pinnacle Health Systems was notified that a business associate, a medical transcription service, had a server compromised in which reports of Pinnacle patients could be viewed online. The server compromise involved the protected health information of 1085 individuals. The protected health information involved in the breach included names, Medicaid ID numbers, dates of birth, and primary physicians. In response to this incident, the covered entity took steps to enforce the requirements of the Privacy & Security Rules. The covered entity immediately discontinued its relationship with the business associate and engaged another medical transcription service. The covered entity also contracted with forensic consultants to ensure that the cause of the compromise was found that that all traces of breached medical reports were removed from online and inaccessible in the future. + +" 2008-10-01 +Gary C. Spinks, DMD, PC MD 1000 Hacking/IT Incident Desktop Computer, Network Server 2014-01-23 2010-09-29 +Cook County Health & Hospitals System IL 556 Theft Desktop Computer 2014-01-23 2010-11-01 +Dean Health Systems, Inc.; St. Mary's Hospital; St. Marys Dean Ventures, Incorporated WI 3288 Theft Laptop 2014-01-23 2010-11-08 +Riverside Mercy Hospital and Ohio/Mercy Diagnostics OH 1000 Improper Disposal Paper 2014-01-23 2003-03-29 +California Therapy Solutions CA 1250 Theft Other Portable Electronic Device, Other 2014-01-23 2010-11-11 +Osceola Medical Center WI Hils Transcription 585 Unauthorized Access/Disclosure Other 2014-01-23 2010-11-25 +Indiana Family and Social Services Administration IN The Southwestern Indiana Regional Council on Aging 757 Theft Laptop 2014-01-23 2010-11-04 +Mankato Clinic MN 3159 Theft Laptop 2014-01-23 2010-11-01 +Geisinger Wyoming Valley Medical Center PA 2928 Unauthorized Access/Disclosure E-mail 2014-01-23 2010-11-03 +Our Lady of Peace Hospital KY 24600 Theft, Loss Other Portable Electronic Device, Other 2014-01-23 2010-03-31 +International Union of Operating Engineers Health and Welfare Fund MD Zenith Administrators, Inc. 800 Theft Paper 2014-01-23 2010-10-25 +Southern Perioperative Services, P.C. AL 2000 Theft Other Portable Electronic Device, Other 2014-01-23 2010-11-17 +Keystone/AmeriHealth Mercy Health Plans PA 808 Loss Other Portable Electronic Device, Other 2014-01-23 2010-09-20 +Ankle + Foot Center of Tampa Bay, Inc. FL 156000 Theft Network Server 2014-06-30 The covered entity's (CE) network server, containing the electronic protected health information (ePHI) of 136,000 patients, was hacked. The types of ePHI involved in the breach were demographic and clinical information, including diagnoses and other treatment data. Following the breach, the CE hired a third party vendor to resolve a data crash and to create a data back-up plan in order to restore office functioning. To implement adequate safeguards, the CE also employed a cloud service with increased security as the new network server. Additionally, the CE contacted the local FBI office to assist with the CE's internal investigation of the breach and provided breach notification to all affected individuals, the media, and HHS. As a result of OCR's investigation, the CE developed and implemented new protocols to comply with the Security Rule. In addition, the CE provided and initiated new trainings for its staff, completed hiring of a new network vendor, implemented a new electronic health records system, and accounted for the disclosures in the affected individuals' medical records. 2010-10-28 +OhioHealth Corporation dba Grant Medical Center OH 501 Theft Laptop, Desktop Computer 2014-01-23 2008-01-01 +Seacoast Radiology, PA NH 231400 Hacking/IT Incident Network Server 2014-01-23 2010-11-12 +Friendship Center Dental Office FL 2200 Theft Laptop 2014-01-23 2010-12-19 +Centra VA 11982 Theft Laptop 2014-01-23 2010-11-11 +St.Vincent Hospital - Indianapolis IN 1848 Hacking/IT Incident Network Server, E-mail 2014-01-23 2010-11-12 +Texas Health Harris Methodist Hospital Azle TX 9922 Theft, Loss Other Portable Electronic Device, Other 2014-01-23 2010-04-07 +Franciscan Medical Group WA 1250 Theft Desktop Computer 2014-01-23 2010-11-18 +State of South Carolina Budget and Control Board Employee Insurance Program (EIP) SC 5596 Hacking/IT Incident Desktop Computer 2014-01-23 2010-11-08 +Lake Woods Nursing & Rehabilitation Center MI 656 Theft Laptop, Desktop Computer 2014-01-23 2010-12-28 +Benefit Resources, Inc. SC Travis Software Corp. 16200 Loss Other Portable Electronic Device, Other 2014-01-23 2010-10-13 +Baptist Memorial Hospital - Huntingdon TN J. A. Still Corporation 4800 Theft Other 2014-04-23 Two diskettes containing the electronic protected health information (ePHI) of approximately 4,754 individuals were lost by the Covered Entity's (CE) Business Associate (BA) after the package containing the diskettes was damaged by the mail carrier. Although one of the diskettes was eventually found, the other diskette was never recovered. The ePHI on the diskettes included names, addresses, dates of birth, social security numbers, and clinical information. Upon discovery of the breach, the CE obtained a copy of the information contained on the diskettes and notified all affected individuals, OCR and the media. Following OCR's investigation, the CE terminated its contract with the BA involved in the incident and provided evidence of the assurances in its BA agreement pertaining to the return or destruction of ePHI. Lastly, the CE entered an accounting of disclosures for each affected individual into its electronic database. 2010-11-27 +Grays Harbor Pediatrics, PLLC WA 12009 Theft Other Portable Electronic Device, Other 2014-01-23 2010-11-23 +Hanger Prosthetics & Orthotics, Inc. TX 4486 Theft Laptop 2014-01-23 "An unencrypted laptop was stolen from an employee offsite. The laptop contained the PHI of 4,486 patients. The protected health information involved in the breach contained names, addresses and procedure codes. Following the breach, the CE filed a police report, notified affected patients and notified the media. Following the discovery of the breach, the covered entity encrypted all existing laptops and implemented a policy requiring all future purchased laptops to be encrypted prior to being issued for use. + +" 2010-11-24 +Baylor Heart and Vascular Center TX 8241 Theft Other Portable Electronic Device, Other 2014-04-23 A portable ultrasound machine containing electronic protected health information (ePHI) of approximately 8,241 individuals was stolen from the covered entity's (CE) facility. The ePHI involved in the breach included patient names, dates of birth, and limited health information. Upon discovery of the breach, the CE conducted a privacy and security assessment of its portable machines to identify vulnerabilities. Following OCR's investigation, the CE updated its privacy and security policies, retrained its employees, and increased physical security to ensure reasonable safeguards. 2010-12-02 +CHC MEMPHIS CMHC, LLC TN 500 Theft Desktop Computer 2014-01-23 2010-12-04 +Jefferson Center for Mental Health CO 546 Theft Paper 2014-01-23 2010-12-13 +Green River District Health Department KY Integranetics 18871 Hacking/IT Incident Network Server 2014-01-23 2011-01-12 +Ortho Montana, PSC MT 37000 Theft, Loss Laptop 2014-02-14 2011-01-08 +Cancer Care Northwest P.S. WA 3100 Theft Paper 2014-06-30 The covered entity (CE) accidentally mailed the protected health information (PHI) of approximately 3,100 individuals to other individuals when a mail-merge process mismatched names and addresses. The PHI involved in the breach included names and indicated that the individuals were patients of the CE. Following the breach, the CE implemented additional safeguards, as well as policies and procedures to ensure mailing list accuracy. As a result of this incident, OCR required the CE to train its workforce members on its newly developed policies and procedures. Additionally, OCR provided technical assistance regarding substitute breach notification methods, including a conspicuous posting on the CE's website. 2011-01-07 +Saint Louis University MO 800 Hacking/IT Incident Desktop Computer 2014-01-23 2010-12-11 +New York City Health & Hospitals Corporation's North Bronx Healthcare Network NY GRM Information Management Services 1700000 Theft Other, Electronic Medical Record 2014-05-28 Unencrypted clinical system backup tapes that contained the electronic protected health information (ePHI) of 1,700,000 individuals were stolen from the unlocked vehicle of an employee of the covered entity's (CE) business associate (BA). The ePHI included names, medical record numbers, social security numbers, addresses, telephone numbers, health plan numbers, dates of birth, dates of admission, dates of treatment, dates of discharge, dates of death, mother's name, next of kin, clinical information related to diagnosis, treatment, prognosis, laboratory tests and results, and medications. Upon discovery of the breach, the CE filed a police report to recover the stolen items and provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE terminated its BA agreement and installed encryption software on backup media. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2010-12-23 +Long Beach Memorial Medical Center CA 2250 Unauthorized Access/Disclosure Other 2014-01-23 2010-12-10 +Walgreen Co. IL Business Express 2700 Theft Other Portable Electronic Device, Other 2014-06-10 2011-01-26 +Charleston Area Medical Center, Inc WV Xforia Web Services 3655 Unauthorized Access/Disclosure Network Server 2014-01-23 2011-02-08 +Mountain Vista Medical Center AZ 2291 Loss Other Portable Electronic Device, Other 2014-01-23 2010-10-13 +Departamento de Salud de Puerto Rico PR 2621 Unknown Desktop Computer 2014-01-23 2010-03-14 +Henry Ford Hospital MI 2777 Loss Other Portable Electronic Device, Other 2014-01-23 2011-01-31 +Central Brooklyn Medical Group, PC NY 500 Theft Paper 2014-06-20 OCR opened an investigation of the covered entity (CE), Preferred Health Partners f/k/a Central Brooklyn Medical Group, after it reported appointment schedules, pathology reports and portions of medical records containing the protected health information (PHI) of 500 individuals were stolen from an office. The PHI included names, ages, telephone numbers, social security numbers, medical insurance information, pathology reports, and other clinical information. Upon discovery of the breach, the CE filed a police report and worked with law enforcement authorities to recover as much of the PHI as possible that was stolen. As a result of OCR's investigation, the CE removed PHI such as social security or medical insurance numbers from tracking logs. In addition, the CE improved safeguards by storing log binders in a locked area and shredding documents regularly. Further, the CE replaced the manual process of printing certain records with an electronic verification system. The CE also archived, stored off site, and locked up all paper records and retrained all staff on its HIPAA policies and procedures. 2010-08-03 +TRICARE Management Activity CO 4500 Unauthorized Access/Disclosure Paper 2014-01-23 2010-06-25 +Blue Cross and Blue Shield of Florida FL 7366 Unknown Other 2014-01-23 2010-10-16 +University Health Services, University of Massachusetts, Amherst MA 942 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2010-09-29 +Omnicare, Inc KY 8845 Theft Laptop 2014-01-23 2011-01-19 +JEFFREY J. SMITH, MD OK 600 Loss Desktop Computer, Other Portable Electronic Device, Other 2014-01-23 2010-11-24 +University of Missouri Health Plan MO Coventry Health Care, Inc. 765 Unauthorized Access/Disclosure Paper 2014-01-23 2011-01-10 +Texas Health Arlington Memorial Hospital TX 654 Unknown Electronic Medical Record 2014-01-23 "The IT department turned on the switch to a BA HIE without notifying patients of the exchange or obtaining authorization. The interface transmitted the PHI of 654 individuals. The PHI disclosed included patient names, addresses, dates of birth, social security numbers, other identifiers, diagnosis/conditions, medications, lab results, other treatment information and financial information. Following the breach, the CE revised the IT process, created a checklist that included notifying the affected departments and provided additional training to IT and registration employees. + +" 2010-12-23 +NYU School of Medicine Faculty Group Practice NY 670 Theft Desktop Computer 2014-06-19 An unencrypted desktop computer that contained the electronic protected health information (ePHI) of 670 individuals was stolen from the covered entity (CE), NYU Langone Medical Center. The ePHI included names, diagnoses, the results of diagnostic tests, and clinical information. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE directed staff to store ePHI on network servers and not on desktops. In addition, the CE improved physical security by installing a locking device to secure the desktop computer and a latch guard on the office door. The CE retrained all staff on its policies and procedures for HIPAA and HITECH compliance. 2011-01-27 +Rape & Brooks Orthodontics, P.C. AL 20744 Theft Desktop Computer, Network Server, Other Portable Electronic Device, Other 2014-01-23 2011-02-03 +Clarksburg - Louis A. Johnson VA Medical Center WV 1470 Unauthorized Access/Disclosure Paper 2014-01-23 2010-10-26 +County of Los Angeles CA 667 Theft Laptop 2014-01-23 2011-02-23 +EISENHOWER MEDICAL CENTER CA 514330 Theft Desktop Computer 2014-01-23 2011-03-11 +Catholic Social Services AK Trisha Elaine Cordova 1700 Theft Laptop 2014-06-30 A personal laptop computer containing the electronic protected health information (ePHI) of 1,700 individuals and approximately 493 adoption home studies was stolen from a contractor's vehicle. The ePHI involved included names, addresses, phone numbers, dates of birth, driver's license numbers, health information, and social security numbers. At the time of the breach, the covered entity (CE) did not have a business associate (BA) contract with the contractor. Following OCR's investigation, the CE developed policies and procedures for obtaining BA contracts as required by the Privacy Rule and verified that the contractor no longer had a business relationship with the CE. OCR obtained assurances that breach notification was provided to the affected individuals, HHS, and the media. 2011-02-01 +Park Avenue Obstetrics & Gynecology, PC AZ 635 Theft Other Portable Electronic Device, Other 2014-01-23 2011-03-25 +Brian J Daniels D.D.S.,Paul R Daniels D.D.S. AZ 10000 Theft Other Portable Electronic Device, Other 2014-01-23 2011-03-01 +MidState Medical Center CT Hartford Hospital 93500 Loss Other 2014-01-23 2011-02-14 +Patient Care Services at Saint Francis, Inc. OK 84000 Theft Network Server 2014-03-13 2011-01-13 +Union Security Insurance Company MO 935 Unauthorized Access/Disclosure Other 2014-01-23 2011-02-18 +Oklaholma State Dept. of Health OK 132940 Theft Laptop, Paper 2014-04-23 2011-04-06 +Aiken Community Based Outpatient Clinic SC 2717 Improper Disposal Paper 2014-01-23 2011-02-16 +Health Net, Inc. CA IBM 1900000 Unknown Other 2014-01-23 2011-01-21 +SW General Inc AZ 566 Theft Paper 2014-01-23 2004-05-01 +Fairview Health Services MN 1215 Loss Paper 2014-01-23 2011-02-19 +Time Insurance Company WI Healthcare Solutions Team, LLC 675 Unauthorized Access/Disclosure Other 2014-04-23 2011-02-01 +Community Action partnership of Natrona County WY 15000 Hacking/IT Incident Desktop Computer 2014-01-23 2011-02-23 +Keith & Fisher, DDS, PA NC 6000 Hacking/IT Incident Network Server 2014-01-23 2011-02-16 +MacNeal Hospital IL 845 Hacking/IT Incident Laptop, Desktop Computer, Network Server, E-mail 2014-03-24 2011-03-10 +West Lake Hospital IL 686 Hacking/IT Incident Laptop, Desktop Computer, Network Server, E-mail 2014-03-24 2011-03-10 +Phoenix Health Plan AZ 9393 Hacking/IT Incident Laptop, Desktop Computer, Network Server, E-mail 2014-04-23 2011-03-10 +MacNeal Physician Group IL 532 Hacking/IT Incident Laptop, Desktop Computer, Network Server, E-mail 2014-03-24 2011-03-10 +Genesis Clinical Laboratory IL 1070 Hacking/IT Incident Laptop, Desktop Computer, Network Server, E-mail 2014-03-24 2011-03-10 +Knox Community Hospital OH 500 Improper Disposal Other 2014-01-23 2010-10-01 +Speare Memorial Hospital NH 5960 Theft Laptop 2014-03-13 2011-04-02 +Methodist Charlton Medical Center TX 1500 Theft Laptop 2014-01-23 "An unencrypted laptop was stolen from a locked office in the hospital. The laptop contained the PHI of 1523 patients. The protected health information involved in the breach contained demographic and clinical data. Following the breach, the CE filed a police report, notified affected patients and notified the media. Additionally, the CE expanded its encryption policy to include more laptops and implemented additional physical safeguards. + +" 2011-04-16 +Drs Edalji and Komer MA 563 Theft Laptop 2014-01-23 2011-04-12 +Reid Hospital & Health Care Services IN 22001 Theft Laptop 2014-01-23 2011-04-02 +Union Security Insurance Company MO 850 Unauthorized Access/Disclosure Other 2014-01-23 2011-03-24 +Indiana Regional Medical Center PA 1388 Theft Paper 2014-01-23 2010-09-28 +MMM Healthcare, Inc. PR 32390 Theft Desktop Computer 2014-01-23 2011-03-08 +PMC Medicare Choice PR 24361 Theft Desktop Computer 2014-01-23 2011-03-08 +CVS CAREMARK AZ 654 Theft, Unauthorized Access/Disclosure Paper 2014-04-23 2011-01-17 +CENTER FOR ARTHRITIS & RHEUMATIC DISEASES FL 8000 Theft Other, Paper 2014-01-23 2011-01-01 +Robert B. Miller, MD CA 620 Theft Laptop 2014-01-23 2011-04-01 +Imaging Center of Garland TX 1031 Improper Disposal Other 2014-01-23 2011-03-15 +New York State Department of Health NY St. Mary's Hospital for Children 550 Theft Paper 2014-06-03 A bag containing 43 pages of protected health information (PHI) of 550 nursing home residents and an encrypted laptop computer were stolen from the vehicle of an employee of the covered entity's (CE) business associate (BA). The PHI included names, dates of birth, gender identities, names of the nursing homes, and Medicaid numbers. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media, and all affected individuals, as well as offering one year of free identity theft protection. Following OCR's investigation, the CE's BA terminated the employee and re-trained its staff on its privacy and security policies, including not leaving laptops in unoccupied vehicles. In addition, the CE reminded all contractors about the need to safeguard confidential information, and reviewed the BA's contractual obligations relating to safeguarding PHI. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2011-04-17 +St. Mary's Hospital for Children NY 550 Theft Paper 2014-06-02 A laptop computer containing the protected health information (PHI) of approximately 550 individuals was stolen from the vehicle of the business associate's (BA) workforce member. The PHI included names, dates of birth, gender identities, names of nursing homes, and Medicaid numbers of the covered entity's (CE) patients. Following the breach, the BA terminated the employee who was involved in the breach and provided credit monitoring services to the affected individuals. The BA also re-trained its staff. Following OCR's investigation, the CE and the BA reviewed the BA's contractual obligations relating to PHI during an in-person meeting. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2011-04-17 +Medicare Fee-for-Service Program MD Cahaba Government Benefit Administrators, LLC 13412 Unauthorized Access/Disclosure Paper 2014-01-23 2011-04-11 +VA Caribbean Healthcare System PR 6006 Theft Paper 2014-06-19 An employee of the covered entity (CE), VA Caribbean Healthcare System, left documents containing the protected health information (PHI) of 6,006 individuals in an unsecure bag at a nursing station. The PHI included names, social security numbers, patient care assignments, patient counts and patient census lists. Upon discovery of the breach, the CE secured the PHI and provided breach notification to HHS, the media, and affected individuals. As a result of OCR's investigation, the CE disciplined and retrained the employee and implemented a procedure that nursing leadership is required to conduct rounds on wards once vacated. The CE also retrained all staff on its privacy and security policies and procedures. 2011-03-30 +Blue Cross Blue Shield of Michigan MI Agent Benefits Corporation 11387 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2010-11-17 +Spartanburg Regional Healthcare System SC 400000 Theft Desktop Computer 2014-01-23 2011-03-28 +Saint Joseph - Berea KY 1986 Theft, Loss Other Portable Electronic Device, Other 2014-04-23 2011-04-14 +Navos WA 2700 Unknown Paper 2014-01-23 2011-03-15 +Dunes Family Health Care, P.C OR Lower Umpqua Hospital 17000 Theft Other Portable Electronic Device, Other 2014-02-14 2011-03-11 +Metropolitan Community Health Services, Inc. NC 1263 Unknown E-mail 2014-04-23 2011-05-18 +TUBA CITY REGIONAL HEALTH CARE CORPORATION AZ 2000 Loss, Improper Disposal Paper 2014-01-23 2011-04-01 +FOOTHILLS NEPHROLOGY, PC SC 1280 Theft Other Portable Electronic Device, Other 2014-01-23 2011-04-28 +Sutter Gould Medical Foundation (SGMF) CA Fidelity National Technology Imaging (FNTI) 1192 Loss Paper 2014-01-23 2011-05-23 +Silverpop Systems Inc. Health and Welfare Plan GA 884 Theft Laptop 2014-01-23 2011-04-15 +New River Health Association WV 950 Unauthorized Access/Disclosure Paper 2014-01-23 2011-04-01 +HealthCare Partners CA 15677 Theft Desktop Computer 2014-01-23 2011-04-17 +Gene S. J. Liaw, MD. PS WA 1105 Loss Other Portable Electronic Device, Other 2014-01-23 2011-04-04 +Blue Cross and Blue Shield of Florida FL 3463 Unauthorized Access/Disclosure Other 2014-01-23 2011-04-11 +NOL, LLC d/b/a Premier Radiology TN 810 Theft Laptop 2014-04-23 2011-05-07 +Advanced Diagnostic Imaging, P.C. TN 705 Theft Laptop 2014-04-23 2011-05-07 +University of Missouri Health Care MO 1288 Unknown Paper 2014-01-23 2011-06-14 +Accendo AZ 175350 Unauthorized Access/Disclosure Paper 2014-01-23 2011-01-01 +Ohio Health Plans OH Area Agency on Aging, Ohio District 5 78042 Theft Laptop 2014-01-23 2011-06-03 +Gail Gillespie and Associates, LLC LA 2000 Theft Laptop, Desktop Computer, Network Server, E-mail, Other Portable Electronic Device, Other, Electronic Medical Record 2014-01-23 2011-06-25 +Health Plan of San Mateo CA 694 Unauthorized Access/Disclosure Paper 2014-01-23 2011-04-25 +Department of Health Care Policy and Financing CO Department of Personnel and Administration 3589 Loss Other 2014-02-14 2011-05-06 +Yanez Dental Corporation CA 10190 Theft Desktop Computer, Network Server 2014-01-23 2011-05-22 +Jackson Health System FL 1562 Unauthorized Access/Disclosure Other, Electronic Medical Record 2014-01-23 2008-10-01 +The Mount Sinai Hospital NY 712 Theft Laptop 2014-06-02 Two unencrypted laptop computers containing the electronic protected health information (ePHI) of 712 individuals were stolen from the covered entity's (CE) office. The ePHI included names, dates of birth, social security numbers, diagnostic reports, and demographic information. Upon discovery of the breach, the CE filed a police report to recover the stolen items. As a result of OCR's investigation, the CE improved physical security by installing an exit alarm lock and surveillance camera, and implementing a policy and procedure requiring managers to monitor inappropriate use of the facility's rear exit. The CE also inventoried its ePHI systems and adopted and implemented policies and procedures for workstation security, encryption, security awareness and training, electronic devices, and media controls. 2011-06-07 +Troy Regional Medical Center AL 880 Unauthorized Access/Disclosure Paper 2014-01-23 2011-03-22 +Lansing Community College MI AssureCare Risk Management 5000 Hacking/IT Incident Network Server 2014-03-24 2011-05-09 +Dr Axel Velez PR 2800 Theft Desktop Computer 2014-03-13 2011-06-19 + DeKalb Medical Center, Inc. d/b/a DeKalb Medical Hillandale GA 7500 Theft Paper 2014-01-23 2010-07-11 +Beth Israel Deaconess Medical Center MA 2021 Hacking/IT Incident Network Server 2014-01-23 2011-04-17 +Gypsum Management and Supply, Inc. Medical and Dental Plan GA Assurecare Risk Management, Inc. 25330 Unauthorized Access/Disclosure Network Server 2014-01-23 2011-05-09 +Andersen Air Force Base, Guam VA 700 Improper Disposal Paper 2014-01-23 2011-05-13 +Molina Medicare CA RxAmerica, a subsidiary of CVS Caremark 4573 Unauthorized Access/Disclosure Paper 2014-01-23 2011-01-01 +Windsor Health Plan TN RxAmerica LLC 1378 Unauthorized Access/Disclosure Paper 2014-01-23 2011-03-01 +Health Care Service Corporation IL 501 Theft Paper 2014-01-23 2011-06-28 +University of Kentucky - UK HealthCare KY 3604 Theft Laptop 2014-04-23 2011-06-07 +Austin Center for Therapy and Assessment, LLC TX 1870 Theft Laptop 2014-04-24 An unencrypted laptop, containing the electronic protected health information (ePHI) of 1,870 individuals, was stolen from the covered entity's (CE) office. The ePHI involved includes clinical evaluation reports, test results, patient names, addresses, phone numbers, and social security numbers. Upon discovery of the breach, the CE notified affected individuals, OCR and the media. Following OCR's investigation, the CE revised its HIPAA policies and procedures, implemented additional physical safeguards in its facility and installed encryption software. 2011-07-08 +Treatment Services Northwest OR 1200 Theft Desktop Computer 2014-01-23 2011-07-08 +Mills-Peninsula Health Services CA 1500 Unauthorized Access/Disclosure Paper 2014-01-23 2009-11-01 +Brigham and Women's Hospital and Faulkner Hospital MA 638 Theft Other Portable Electronic Device 2014-06-30 A covered entity's (CE) workforce member lost an external hard drive containing the electronic protected health information (ePHI) of 638 individuals while traveling. The external hard drive included names, medical record numbers, dates of admission, medications, diagnoses, and treatment information. The CE notified HHS, the media, and all individuals affected regarding the breach and provided individuals with identity protection services. Following the breach, the CE sanctioned the workforce member involved and retrained the workforce member and division staff on safeguards for ePHI. In addition, the CE established a mitigation workgroup to review policies and procedures regarding the protection of ePHI and created a new external hard drive encryption policy. OCR obtained assurances that the CE implemented the corrective action listed above. 2011-06-21 +Ashley Industrial Molding, Inc. Employee Welfare Benefit Plan IN AssureCare Risk Management, Inc. 506 Hacking/IT Incident Network Server 2014-01-23 2011-05-09 +Monmouth Medical Center NJ MedAssets 6443 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 6,443 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Monmouth Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +Clara Maass Medical Center NJ Med Assets 8795 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 8,795 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Clara Maass Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +Newark Beth Israel Medical Center NJ MedAssets 15015 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 15,015 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Newark Beth Israel Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +Saint Barnabas Medical Center NJ MedAssets 6179 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 6,179 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Saint Barnabas Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +Washington State Department of Social and Health Services WA 3950 Unauthorized Access/Disclosure Paper 2014-01-23 2011-07-01 +St. Francis Hospital DE 948 Loss Other Portable Electronic Device, Other 2014-06-10 2011-06-01 +Reznick Group, P.C. MD Assure Care Risk Management 2459 Hacking/IT Incident Network Server 2014-03-25 2011-05-09 +The Neurological Institute of Savannah & Center for Spine GA 63425 Theft Other Portable Electronic Device, Other 2014-01-23 2011-07-02 +Kimball Medical Center NJ MedAssets 6785 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 6,785 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Kimball Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +Community Medical Center NJ MedAssets 6950 Theft Other Portable Electronic Device, Other 2014-06-19 "An unencrypted hard drive containing the electronic protected health information (ePHI) of 6,950 individuals was stolen from an employee of the covered entity's (CE) business associate (BA), MedAssets. The ePHI included names, dates of birth, social security number, account numbers, medical record numbers, charges incurred, amounts paid, admission and discharge dates, and information regarding health insurance and eligibility for applicable governmental benefit programs. Upon discovery of the breach, the CE, Community Medical Center, filed a police report, provided breach notification to HHS, the media, and affected individuals, and posted substitute notification on its website. As a result of OCR's investigation, the BA retrained the employee, instructed all employees to stop using any type of external storage device that contains ePHI, and recalled and destroyed all unencrypted external hard drives that contained ePHI. In addition, the BA improved technical safeguards by encrypting external hard drives and installing a new software system that monitors, controls and encrypts data leaving the BA's computers. The BA also hired an IT security analyst to supplement its security program. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + + + +" 2011-06-24 +American Health Medicare PR Accuprint 5848 Theft Other 2014-06-03 The covered entity's (CE) business associate (BA) erroneously sent explanation of benefits letters (EOBs) containing the protected health information (PHI) of 5,848 individuals to other individuals. The PHI included names, addresses, current procedural terminology codes (CPT), explanations of CPT codes, providers' names, and dates of service. Upon discovery of the breach, the CE provided notice to the individuals affected by the breach but did not notify the media. As a result of OCR's investigation, OCR provided technical assistance regarding the requirements of the Breach Notification Rule to the CE and the CE published a media notice. In addition, the CE developed policies and procedures requiring quality control checks on the BA. In addition, the BA adopted a new software system that validates the contents of the EOBs prior to mailing. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use of PHI and required the BA to safeguard all PHI. 2011-06-01 +Texas Health Presbtyerian Hospital Flower Mound TX Texas Health Partners 10345 Theft Laptop 2014-01-23 2011-06-21 +Capron Rescue Squad District IL 815 Unauthorized Access/Disclosure Laptop 2014-01-23 2011-02-05 +Cook County Health & Hospitals System IL MedAssets 32008 Theft Other Portable Electronic Device, Other 2014-01-23 2011-06-24 +Lexington VAMC KY 1432 Theft Laptop, Other Portable Electronic Device, Paper 2014-06-03 "The covered entity's (CE) workforce member impermissibly stored the protected health information (PHI) of 1,432 individuals in a personal computer and other portable electronic media in order to conduct research. The PHI included social security numbers, names, initials, ages, and diagnoses. Additional PHI was found in the workforce member's residence. The CE provided breach notification to a total of 1,890 affected individuals and HHS. Following the breach, the responsible workforce member is no longer employed by the CE. + + + +OCR opened a compliance review of VA Medical Centers and is consolidating the investigation of this incident into the compliance review. + +" 2011-05-23 +Dr. Victoria Falcone, Falcone Cosmetic Services, PC, Falcone Cosmetic Services of NJ, PC PA SpaMed Solutions, LLC, Edward McMenamin President, 3000 Theft, Unauthorized Access/Disclosure Laptop, Desktop Computer, Network Server, E-mail, Other Portable Electronic Device, Other, Electronic Medical Record, Paper 2014-06-10 2011-08-14 +HEALTH RESEARCH INSTITUTE, INC., PFEIFFER TREATMENT CENTER IL 2000 Theft Desktop Computer, Network Server 2014-01-23 2011-07-01 +Stanford Hospital & Clinics CA Multi-Speciality Collection Services, LLC 19651 Unauthorized Access/Disclosure Other 2014-01-23 2010-09-09 +Muir Orthopaedic Specialists, A Medical Group Inc. CA 1800 Theft Paper 2014-01-23 2011-07-27 +NEA Baptist Clinic AR 3116 Hacking/IT Incident Network Server 2014-01-23 2011-07-12 +Jonathan Noel MD IN 2059 Theft Other Portable Electronic Device, Other 2014-01-23 2011-07-13 +Texas Health and Human Services Commission TX 1696 Theft Laptop 2014-01-23 "An unencrypted laptop was stolen from an employee's vehicle. The laptop contained the ePHI of 1,696 patients. The information at issue included patient names, dates of birth, gender, Medicaid identification numbers, procedure codes and diagnosis. Following discovery of the breach, the CE notified affected patients and notified the media. Following the breach, the CE confirmed encryption of laptops per CE's policy and sanctioned three involved employees. + +" 2011-03-10 +University of Wisconsin Oshkosh WI Living Healthy Community Clinic 3000 Hacking/IT Incident Desktop Computer 2014-01-23 2011-07-18 +Centro de Ortodoncia Inc. PR 2000 Theft Paper 2014-06-20 OCR opened an investigation of the covered entity (CE), Dr. Pedro Valentin, after it reported boxes containing the protected health information (PHI) of 2,000 individuals were moved from the CE's office. The PHI included names, account numbers, responsible party in charge of account, and method of payment. OCR's investigation revealed that the individual who removed the PHI was the CE's wife and business partner. The CE advised OCR that he knew his wife/partner was removing the boxes for the purpose of ascertaining the amount of monies the CE was receiving and that he is in the process of dissolving the partnership. OCR concluded that the actions alleged in the breach report did not amount to a breach. 2010-05-06 +John T. Melvin, M.D.& Associates TX 2541 Theft Paper 2014-03-13 2011-08-09 +Diversified Resources, Inc. GA 863 Theft Laptop 2014-01-23 2011-08-11 +VA Gulf Coast Veterans Health Care System MS 1797 Theft Paper 2014-06-20 "The covered entity (CE), U.S. Department of Veterans Affairs (VA), Gulf Coast Veterans Health Care System, Biloxi Veterans Affairs Medical Center (Biloxi VAMC) reported that the office of an employee was vandalized. Paper files were found on the office floor, and the protected health information (PHI) of approximately 1,814 individuals was compromised. The PHI included full names, social security numbers, dates of birth, and medical diagnoses. The CE provided breach notification to HHS, the media and affected individuals. Following the breach, VA police at the facility reviewed procedures and continued foot patrols to ensure office doors are locked during non-business hours. The CE provided additional training to workforce members of the affected department on its physical security policies and procedures to improve safeguards for PHI. OCR obtained assurances that the CE implemented the corrective action listed above. + + + +" 2011-07-21 +Freda J Bowman MD PA TX 1300 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2011-09-20 +Bonney Lake Medical Center and Mythili R. Ramachandran, MD WA 2367 Theft Laptop, Desktop Computer 2014-02-14 2011-08-12 +United States Steel Corporation Plan for Active Employee Insurance Benefits and the United States Steel Corporation Plan for Retiree Insurance Benefits PA Benefits Administration Services, Inc. 4000 Loss Other Portable Electronic Device, Other 2014-03-24 2011-08-15 +VA Illiana Health Care System IL 518 Loss Paper 2014-01-23 2011-07-14 +Health Texas Provider Network TX 1259 Theft Laptop 2014-03-13 2011-07-27 +Blue Cross of Northeastern Pennsylvania PA AllOne Health Management Solutions, Inc. 507 Theft, Unauthorized Access/Disclosure Laptop, Paper 2014-03-24 2011-09-09 +NYU Hospital for Joint Diseases Inventory Management Department NY 2600 Theft Paper 2014-06-20 A box containing 2,600 paper records of tissue implants used in surgeries was discarded by a waste disposal contractor of the covered entity (CE), NYU Hospital for Joint Diseases Inventory Management Department, when the box was not property secured. The box contained the protected health information (PHI) of 2,239 individuals and included names, dates of birth, dates of surgery, surgeon names, procedures, and types and serial numbers of the tissues used in the surgeries. Upon discovery of the breach, the CE contacted the waste disposal contractor and determined that the documents were discarded and buried in a landfill out of state. The CE provided breach notification to HHS, the media, and affected individuals, and posted substitute notice on its website. As a result of OCR's investigation, the CE improved safeguards by storing all tissue records in a locked cabinet and requiring management to store the keys. In addition, the CE counseled the employees involved in the incident and retrained all staff on its policies and procedures for safeguarding PHI. The CE also implemented a plan to conduct reviews of HIPAA compliance, including both physical access and physical security risks. 2011-06-23 +WAYNE HIGHLANDS SCHOOL DISTRICT PA FIRST PRIORITY LIFE INSURANCE COMPANY 579 Theft, Unauthorized Access/Disclosure Paper 2014-06-10 2011-09-09 +Summit Medical Group, PLLC TN 731 Theft Paper 2014-01-23 2011-09-04 +MAPFRE Life PR 2209 Theft Other 2014-03-13 2011-08-05 +American Continental Insurance Company TN Futurity First Insurance Group 690 Theft Other Portable Electronic Device, Other 2014-01-23 2011-07-28 +United of Omaha Life Insurance Company NE Futurity First Insurance Group 1631 Loss Other Portable Electronic Device, Other 2014-01-23 2011-07-28 +Mutual of Omaha Insurance Company NE Futurity First Insurance Group 705 Theft Other Portable Electronic Device, Other 2014-01-23 2011-07-28 +Henry Ford Health System MI 520 Theft Desktop Computer 2014-01-23 2011-08-08 +Indiana University IN 3266 Theft Laptop 2014-01-23 2011-08-16 +Adult & Pediatric Dermatology, PC MA 2200 Theft Other Portable Electronic Device, Other 2014-01-23 2011-09-14 +The Nemours Foundation FL 1055489 Loss Other 2014-01-23 2011-08-10 +California Industrial Medicine, Inc. CA Thomas J O'Laughlin, MD 700 Theft, Unauthorized Access/Disclosure Paper 2014-02-14 2011-09-28 +InStep Foot Clinic, P.A. MN 2600 Theft Laptop, Electronic Medical Record 2014-01-23 2011-08-28 +North Memorial MN Accretive Health, Inc 6697 Theft Laptop 2014-01-23 2011-07-25 +Lahey Clinic Hospital, Inc. MA 599 Theft Laptop 2014-03-13 2011-08-12 +UnitedHealth Group health plan single affiliated covered entity MN Futurity First Insurance Group 3994 Theft Other 2014-01-23 2011-07-28 +Good Samaritan Hospital MD 1500 Theft Paper 2014-01-23 2011-09-09 +Amerigroup Community Care of New Mexico, Inc NM 1537 Theft Paper 2014-01-23 2011-07-15 +Florida Hospital FL 12784 Unauthorized Access/Disclosure Electronic Medical Record 2014-02-19 2011-08-10 +Thomas Jefferson University Hospitals, Inc. PA 3150 Theft Other 2014-01-23 2011-09-06 +Lankenau Medical Center PA 500 Theft Other 2014-01-23 2011-09-06 +Spectrum Health Ssytems, Inc. MA 14750 Theft Desktop Computer 2014-03-13 2011-08-24 +Conway Regional Medical Center AR 1472 Loss Other 2014-01-23 2011-08-24 +Concordia Plan Services MO HITS Scanning Solutions, Inc. 7059 Loss Other 2014-01-23 2011-05-10 +Stone Oak Urgent Care & Family Practice TX Stone Oak Urgent Care & Family Practice 6672 Theft, Loss Desktop Computer 2014-01-23 2011-10-23 +Indiana University School of Optometry IN 757 Unauthorized Access/Disclosure Network Server 2014-01-23 2011-08-12 +Brevard Emergency Services, P.A. FL 2200 Theft Paper 2014-04-23 2011-08-26 +Georgetown University Hospital DC 1526 Loss Other Portable Electronic Device, Other 2014-03-24 2011-09-09 +Morris Heights Health Center NY 927 Theft Laptop 2014-06-03 An unencrypted laptop computer containing the electronic protected health information (ePHI) of 927 individuals was stolen from the covered entity's (CE) school based health center. The ePHI included names, dates of birth, sex, ethnicities, height, weight, body mass index data, complete physical examination information such as asthma and obesity information, health action plans, and enrollment dates. Upon discovery of the breach, the CE filed a police report to recover the stolen laptop. As a result of OCR's investigation, the CE purchased locks to physically secure its' school health computers to the desks where the computers are located. In addition, the CE encrypted all portable devices' hard drives and installed software to track portable devices. The CE also retrained all staff on its policies and procedures for using and securing ePHI. 2011-08-27 +network180 MI Thresholds Inc. 1100 Theft Paper 2014-03-24 2011-09-16 +Premier Imaging NC 551 Unknown Paper 2014-01-23 "A newly hired employee impermissibly took patient registration documents home. The records taken included the protected health information of 551 patients. The information at issue included names, addresses, birth dates, social security numbers, and driver's license numbers. As a result, the CE terminated the employee, provided notice to the affected individuals, amended registration procedures, implemented additional safeguards for such information, and offered identity theft protection to the affected individuals. + +" 2011-09-14 +The Good Samaritan Hospital of Cincinnati, Ohio OH Pitney Bowes Management Services, Inc. 1089 Theft Desktop Computer 2014-03-24 2011-09-03 +Bethesda Hospital, Inc. OH Pitney Bowes Management Services, Inc. 946 Theft Desktop Computer 2014-03-24 2011-09-03 +Julie A. Kennedy, D.M.D., P.A. FL 2900 Theft Network Server 2014-01-23 2011-09-30 +KCI USA, Inc. TX 567 Theft Other Portable Electronic Device, Other 2014-01-23 2011-09-08 +Lebanon Internal Medicine Associates PA 55000 Improper Disposal Network Server 2014-01-23 2011-09-10 +St. Joseph Medical Center MD 5000 Theft Other, Paper 2014-03-24 2011-09-11 +TRICARE Management Activity (TMA) VA Science Applications International Corporation (SA 4900000 Loss Other 2014-01-23 2011-09-13 +UCLA Health System CA 2761 Theft Other Portable Electronic Device, Other 2014-01-23 2011-09-06 +Logan County Emergeny Ambulance Service Authority WV 12563 Theft, Loss Laptop 2014-01-23 2011-10-01 +Lawrence Memorial Hospital KS Mid Continent Credit Services, Inc. 8275 Unauthorized Access/Disclosure, Other Other 2014-04-23 2011-09-20 2011-10-28 +Sutter Medical Foundation AL 943434 Theft Desktop Computer 2014-01-23 2011-10-15 +Medcenter One ND 650 Theft Laptop 2014-01-23 2011-10-21 +Dallas County Hospital District dba Parkland Health & Hospital System TX 2464 Unauthorized Access/Disclosure Electronic Medical Record, Paper 2014-01-23 2011-09-05 +University of Kentucky UK HealthCare KY 878 Loss Other Portable Electronic Device 2014-01-23 2011-09-25 +State of Tennessee Sponsored Group Health Plan TN 1770 Unauthorized Access/Disclosure Paper 2014-01-23 "An equipment operator at the state's postal facility set the machine to insert four (4) pages per envelope instead of one (1) page per envelope, which caused the PHI of four individuals to be sent to one address per envelope. The error affected approximately 1770 enrollees. The letters contained information such as names, addresses, birth dates, and social security numbers. As a result, the CE retrained the employee, submitted a breach report to HHS, provided notice to the affected individuals, notified the media, created a toll-free number for information regarding the incident, posted notice on its website, modified policies to remove the SSN on templates for future mailings, and offered identity theft protection to the affected individuals. Following the OCR investigation, the CE provided reviewed its policies and procedures to ensure adequate safeguards are in place. + +" 2011-10-06 +Cleveland Clinic Florida FL 772 Loss Other 2014-04-23 2011-10-03 +Jay C. Platt, DDS IN 10705 Theft Other 2014-03-24 2011-10-06 +Rite Aid Corporation PA 2900 Other Paper 2014-01-23 2011-10-07 +Advanced Occupational Medicine Specialists IL Blue Vantage Group 7226 Unauthorized Access/Disclosure Network Server 2014-01-23 2011-10-12 +Open MRI of Chicago IL Nation Wise Machine Buyers 2000 Improper Disposal Paper 2014-01-23 2011-09-06 +University of Nebraska Medical Center NE 611 Theft Paper 2014-04-23 2011-11-15 +Roberts S. Smith M.D. Inc. GA 17000 Theft Laptop 2014-01-23 2011-10-17 +Paul C. Brown, MD, PS WA 4693 Theft Other 2014-02-14 2011-10-14 2011-10-17 +Molina Healthcare of California CA 11081 Other Paper 2014-01-23 2009-09-23 +Aegis Sciences Corporation TN 2185 Theft Laptop, Other Portable Electronic Device 2014-04-23 OCR opened an investigation of the covered entity (CE), Aegis Science Corp., after the CE reported that a laptop computer and unencrypted external hard drive containing the electronic protected health information (ePHI) of 2,185 individuals were stolen from a workforce member's vehicle. The ePHI included social security numbers, driver's license numbers, and other demographic information, as well as bank account information of fourteen individuals and credit card information of three individuals. Upon discovering the breach, the CE filed a police report and hired a private investigator to recover the stolen items. The CE also initiated plans to encrypt laptops, revise security procedures, retrain employees, and offer credit monitoring to affected individuals. As a result of OCR's investigation, the CE completed a security risk analysis and risk management report and implemented new security policies and procedures to ensure adequate safeguards to protect ePHI. The CE also provided media notification in the two localities with greater than 500 individuals affected. Additionally, the CE encrypted all employee computers and removable media containing ePHI and retrained employees on the CE's confidentiality and security policies. 2011-11-22 +Soundpath Health, Inc WA 7581 Theft Laptop 2014-02-14 2011-11-22 +Concentra Health TX 870 Theft Laptop 2014-01-23 2011-11-30 +Sleep HealthCenters LLC MA 2988 Theft Laptop 2014-03-13 2011-11-23 +Smile Designs FL 1670 Theft Desktop Computer, Network Server 2014-01-23 2011-12-01 +PBH NC Alamance Caswell Local Management Entity 50000 Unauthorized Access/Disclosure, Other Network Server, E-mail 2014-01-23 2011-11-15 +CardioNet, Inc PA 1300 Theft Laptop 2014-01-23 2011-11-10 +MDwise, Inc. IN RightNow Technologies 2700 Unauthorized Access/Disclosure Other 2014-03-24 2011-02-10 +Ford Motor Company MI WageWorks, Inc. 1700 Other Paper 2014-03-24 2012-01-03 +Foundation Medical Partners NH 771 Theft Paper 2014-06-02 Without permission from the covered entity (CE), an employee provided a list of patient's names to a local counseling center as the employee was leaving the CE to begin employment at the new counseling center in an attempt to coordinate care of the patients she was treating. The list, containing the PHI of approximately 771 individuals, included names, dates of birth, addresses, phone numbers, names of the insurance carriers, and facility codes. Following the disclosure, the CE provided breach notification to HHS, the media, and all individuals affected and sanctioned the former employee for violating its policies and procedures. The CE also changed its procedures for list management. The CE sent a reminder to all of its health care providers regarding the handling of PHI and made plans to provide HIPAA compliance information in a quality assurance newsletter. 2011-11-19 2011-12-01 +Kansas Department on Aging KS 7757 Theft Laptop 2014-01-23 2012-01-11 +Delta Dental of California CA 11646 Other Paper 2014-01-23 2011-12-22 2011-12-23 +Muskogee Regional Medical Center OK 844 Loss Other 2014-01-23 2011-12-05 +Department of Medical Assistance Services VA ACS, Affiliated Computer Services, Inc., A Xerox Company 1444 Unauthorized Access/Disclosure, Other Paper 2014-01-23 2011-11-02 2011-11-16 +Oldendorf Medical Services, PLLC NY 549 Theft Laptop 2014-06-02 OCR opened an investigation of the covered entity (CE) after it reported two unencrypted laptops were stolen that contained the electronic protected health information (ePHI) of 549 individuals. The ePHI included names, dates of birth, diagnostic test results, and social security numbers. Upon discovery of the breach, the CE filed a police report to recover the stolen items. As a result of OCR's investigation, the CE installed security cameras and new door locks and changed the codes to the outside entrance keypad lock. The CE also encrypted laptop computers. 2012-01-17 +St.Vincent Physician Network IN 1423 Theft, Unauthorized Access/Disclosure Paper 2014-03-24 2010-12-01 2011-11-21 +Flex Physical Therapy WA 3100 Theft Desktop Computer 2014-01-23 2011-12-30 +Metro Community Provider Network CO 3200 Hacking/IT Incident, Other E-mail 2014-01-23 2011-12-05 +University of Miami FL 1219 Theft Other Portable Electronic Device 2014-01-23 2011-11-24 +UnitedHealth Group health plan single affiliated covered entity MN 6678 Other Paper 2014-03-24 2011-12-15 +Triumph, LLC NC 2000 Theft Laptop 2014-01-23 2011-12-13 +Fairview Health Services MN Accretive Health 14000 Theft Laptop 2014-01-23 2011-07-25 +Loma Linda University Medical Center (LLUMC) CA 1366 Other Paper 2014-01-23 2011-12-19 +Ford Motor Company Salaried Health Reimbursement Arrangement (HRA) Plan MI Affiliated Computer Services, Inc. (ACS, Inc.) A Xerox Company 1700 Other Other 2014-03-24 2011-12-29 +Medco Health Solutions, Inc. NJ 1287 Theft Paper 2014-06-20 " + +The covered entity (CE), Medco Health Solutions, mailed letters with incorrect addresses after a programming code in its mailing software caused corruption of its data. The mailing contained the protected health information (PHI) of 4,341 individuals and included names, medication name and prescription number. The CE provided breach notification to HHS, the media, and affected individuals. Upon discovery of the breach, the CE immediately ceased using the update to its mailing software system. As a result of OCR's investigation, the CE corrected the update to its mailing software system and established manual and automated quality control processes. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. + +" 2011-11-30 +Lakeview Medical Center WI 698 Theft Laptop 2014-01-23 2012-01-04 +Goshen Health System, Inc. IN 660 Hacking/IT Incident Other 2014-01-23 2011-12-22 +Georgetown University Hospital DC 1549 Unauthorized Access/Disclosure Paper 2014-01-23 2011-11-01 +Motion Picture Industry Health Plans (MPI) CA 703 Other Other 2014-02-14 2009-09-23 2011-12-02 +Ochsner Health System LA 2088 Loss Other Portable Electronic Device 2014-01-23 2012-01-19 +Applegate Valley Family Medicine OR Dr. Trandinh 2300 Theft, Unauthorized Access/Disclosure Laptop 2014-01-23 2011-12-01 2011-12-17 +CardioNet, Inc. PA 728 Theft Laptop 2014-01-23 2011-12-29 +Presbyterian Healthcare Services NM Beth Barrett Consulting, LLC 7000 Theft Laptop 2014-03-13 2011-12-29 +Alliant Health Plans, Inc. GA Catalyst Health Solutions, Inc. 632 Unauthorized Access/Disclosure Other 2014-01-23 2012-01-01 +FIRST MEDICAL CENTER, INC. PR T&P CONSULTING, INC. D/B/A QUANTUM 7706 Theft Laptop 2014-06-13 An unencrypted laptop computer and external hard drive containing the electronic protected health information (ePHI) of 7,706 individuals were stolen from a staff member of the covered entity's (CE) business associate (BA). The ePHI included names, ages, sex, social security numbers, medical services provided, diagnosis codes, and dates of service. Upon discovery of the breach, the CE filed a police report to recover the stolen items and provided breach notification to HHS, the media, and all individuals affected by the breach. As a result of OCR's investigation, the CE had its BA conduct a risk analysis, implement new security policies and procedures to ensure adequate safeguards to protect ePHI, and retrain its employees. In addition, the CE also had its BA change its security practices to include encryption on all laptops and restrict the use of portable media devices. OCR obtained assurances that the CE implemented the corrective action listed above and required two additional corrective actions. OCR identified the need for the CE to complete a risk assessment and implement certain security policies and procedures. 2012-01-11 +Lee Miller Rehabilitation Associates MD 10480 Theft Network Server 2014-01-23 2012-01-15 +Jeremaih J. Twomey, F.A.C.P., P.A. TX Jeremaih J. Twomey, F.A.C.P., P.A. 2559 Theft Other 2014-01-23 2011-12-31 +Anchorage Community Mental Health Services Inc. AK 2743 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2011-12-20 2012-01-04 +Robley Rex VA Medical Center KY 1182 Other Paper 2014-01-23 2012-01-09 +Indiana Internal Medicine Consultants IN 20000 Theft Laptop 2014-06-24 A laptop computer that contained the electronic protected health information (ePHI) of approximately 20,000 individuals was stolen from the covered entity's (CE) laboratory manager's office. The ePHI involved in the breach included patients' names, dates of birth, clinic identification numbers, and laboratory results. Following the breach, the CE reported the theft to the building management company. The management company investigated the theft and determined that cleaning personnel had stolen the laptop. The company reported that the patient information was not compromised, as the database could not be accessed without propriety software and specialized assistance. As a result of OCR's investigation, physical security was improved by housing the replacement laptop in a locked drawer in a locked office with limited staff access. The CE also implemented a new policy prohibiting the storage of PHI on the laptop computer and updated additional policies and procedures to enhance safeguards for systems containing PHI. 2012-02-11 +Policlinica La Familia IPA 343 PR T & P Consulting, Inc. d/b/a Quantum Health Consulting 5994 Theft Laptop 2014-06-03 "An unencrypted laptop computer and external hard drive containing the electronic protected health information (ePHI) of 5,994 individuals were stolen from a staff member of the covered entity's (CE) business associate (BA). The ePHI included names, ages, sex, social security numbers, medical services provided, diagnosis codes, and dates of service. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media and all affected individuals. As a result of OCR's investigation, the CE had its BA conduct a risk analysis, implement new security policies and procedures to ensure adequate safeguards to protect ePHI, and retrain its employees. In addition, the CE also had its BA change its security practices to include encryption on all laptops and restrict the use of portable media devices. OCR obtained assurance that the CE implemented the corrective action listed above and required one additional corrective action. OCR identified the need for the CE to implement certain security policies, procedures and controls. + + + +" 2012-01-11 +Servicios Medicos Integrados de Fajardo PR T & P Consulting, Inc. d/b/a Quantum Health Consulting 10000 Theft Laptop, Other Portable Electronic Device 2014-04-23 The covered entity (CE) filed a breach report with OCR after an external hard drive and laptop computer containing electronic protected health information (ePHI) of 39,609 individuals were stolen from the CE's Business Associate (BA). The ePHI included names, ages, sex, social security numbers, medical services provided, diagnosis codes, and the dates of the service. Immediately following the breach, the CE conducted a risk assessment, filed a breach report and provided OCR a copy of its BA agreement. Additionally, the CE notified all affected individuals of the breach and issued a press release. As a result of OCR's investigation, the CE required the BA to revise its security practices to include laptop encryption and restrictions on the use of portable media devices as outlined in the BA's newly developed security policies and procedures. 2012-01-11 +Proveedores Aliados por tu SAlud PR Quantum Health Consulting 4645 Theft Laptop 2014-06-20 "OCR opened an investigation of the covered entity (CE), First Proveedores Aliados Por Tu Salud, after it reported an unencrypted laptop computer and external hard drive containing the electronic protected health information (ePHI) of 4,645 individuals were stolen from a staff member of the CE's business associate (BA), Quantum Health. The ePHI included names, age, sex, social security numbers, medical services provided, diagnosis codes, and the dates of service. Upon discovery of the breach, the CE filed a police report and provided breach notification to all individuals affected by the breach, HHS, and the media. As a result of OCR's investigation, the CE had its BA conduct a risk analysis and implemented new security policies and procedures to ensure adequate safeguards to protect ePHI and retrain its employees. In addition, the CE also had its BA change its security practices to include encryption on all laptops and restricted the use of portable media devices. + +" 2012-01-12 +Centro de Servicios de Cuidados Dirigidos, Inc. d/b/a Metro Salud grupo Profesional PR T&P Consulting, INC. d/b/a Quantum Health Consulting 27098 Theft Laptop 2014-06-20 OCR opened an investigation of the covered entity (CE), Centro De Servicios de Cuidados Dirigidos, Inc. d/b/a Metro Salud grupo Profesional, after it reported an unencrypted laptop computer and external hard drive containing the electronic protected health information (ePHI) of 27,098 individuals were stolen from a staff member of the CE's business associate (BA), Quantum Health. The ePHI included names, age, sex, social security numbers, medical services provided, diagnosis codes, and the dates of service. Upon discovery of the breach, the BA filed a police report and provided breach notification to the media, and all affected individuals. The CE provided breach notice to HHS. As a result of OCR's investigation, the CE had its BA conduct a risk analysis and implemented new security policies and procedures to ensure adequate safeguards to protect ePHI and retrain its employees. In addition, the CE also had its BA change its security practices to include encryption on all laptops and restricted the use of portable media devices. The CE also terminated its BA agreement with the BA. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2012-01-11 +Kern Medical Center CA 1431 Theft Paper 2014-01-23 2012-02-25 +William F. DeLuca Jr., M.D. NY 577 Theft Laptop 2014-06-02 OCR opened an investigation of the covered entity (CE) after it reported two unencrypted laptops were stolen that contained the electronic protected health information (ePHI) of 577 individuals. The ePHI included names and pictures. Upon discovery of the breach, the CE filed a police report to recover the stolen items. As a result of OCR's investigation, the CE encrypted its computers, changed the locks to a numbered key system, and installed a lock to secure portable devices in storage. In addition, the CE started using identification numbers instead of names on patients' files. The CE also revised its security policy and trained all staff on its policies. 2012-01-16 +Grupo Medico IPA -341 PR Quantum Health Consulting 7923 Theft Laptop 2014-06-20 An unencrypted laptop computer and an external hard drive containing the electronic protected health information (ePHI) of 7,923 individuals were stolen from a staff member of the CE's business associate (BA). The ePHI included names, ages, gender, social security numbers, medical services provided, diagnosis codes, and dates of service. Upon discovery of the breach, the CE filed a police report to recover the stolen items. The CE also provided breach notification to all affected individuals, HHS, and the media. As a result of OCR's investigation, the CE had its BA conduct a risk analysis, implement new security policies and procedures to ensure adequate safeguards to protect ePHI, and retrain its employees. The CE also had its BA change its security practices to include encryption on all laptops and restrict the use of portable media devices. 2012-01-11 +Advanced Clinical Research Institute CA 875 Theft Paper 2014-01-23 2012-01-26 +Access Medical Group -IPA 344 PR T&P Consulting, INC DBA Quantum HC 7606 Theft Laptop, Other Portable Electronic Device 2014-06-13 An unencrypted laptop computer and external hard drive containing the electronic protected health information (ePHI) of 39,609 individuals were stolen from a staff member of the covered entity's (CE) business associate (BA). The ePHI included names, ages, sex, social security numbers, medical services provided, diagnosis codes, and dates of service. Upon discovery of the breach, the CE filed a police report and provided breach notification to HHS, the media and all affected individuals. As a result of OCR's investigation, the CE had its BA conduct a risk analysis, implement new security policies and procedures to ensure adequate safeguards to protect ePHI, and retrain its employees. In addition, the CE also had its BA change its security practices to include encryption on all laptops and restrict the use of portable media devices. OCR obtained assurance that the CE implemented the corrective action listed above and required one additional corrective action. OCR identified the need for the CE to implement certain security policies, procedures and controls. 2012-01-11 +Georgia Health Sciences University GA 513 Theft Laptop 2014-01-23 2012-01-18 +Baylor Heart and Vascular Center, LLP TX 1972 Theft Other Portable Electronic Device 2014-01-23 2012-01-26 +Chicago Musculoskeletal Institute/Metro Orthopedics IL 750 Other Network Server 2014-03-24 2011-12-31 +Tufts Associated Health Maintenance Organization, Inc. and Tufts Insurance Company MA Caremark PCS Health, L.L.C. (formerly known as Caremark PCS Health, L.P.) 3482 Other Paper 2014-01-23 2012-01-17 2012-02-02 +Duke University Health System NC 1370 Unauthorized Access/Disclosure Other 2014-04-23 2008-07-01 2011-11-30 +St. Joseph's Medical Center CA 712 Theft Paper 2014-01-23 2012-02-02 +UnitedHealth Group health plan single affiliated covered entity MN 3537 Unauthorized Access/Disclosure Other 2014-03-24 2011-06-28 +CenterLight Healthcare NY 642 Unauthorized Access/Disclosure E-mail 2014-01-23 2012-01-27 +Lake Granbury Medical Center TX 502 Theft Paper 2014-01-23 2012-02-13 +County of Wayne Department of Personnel/Human Resources Benefits Administration Division MI 1229 Unauthorized Access/Disclosure E-mail 2014-06-10 2012-03-16 +St. Elizabeth's Medical Center MA 6831 Loss Paper 2014-01-23 2012-02-01 +The Neighborhood Christian Clinic AZ 9565 Loss Other Portable Electronic Device 2014-01-23 2012-02-07 +AccentCare Home Health of California, Inc. Medicare # 057564 CA state License # 080000226 CA 1000 Unauthorized Access/Disclosure E-mail 2014-01-23 2012-04-20 2012-04-21 +Seton Health Plan TX HealthLOGIX 555 Unauthorized Access/Disclosure Paper 2014-01-23 2012-03-09 +awklein a med corp CA David Charles Rish 2000 Theft Other 2014-01-23 2011-02-01 +Utah Department of Health UT Utah Department of Technology Services 780000 Hacking/IT Incident Network Server 2014-01-23 2012-03-10 2012-04-02 +IU Medical Group IN 1000 Improper Disposal Paper 2014-01-23 2012-04-11 +Rhinebeck Health Center/Center for Progressive Medicine NY 6745 Theft Desktop Computer, Network Server 2014-06-03 The CE's network server and two local computers were hacked and compromised by a computer virus which resulted in the disclosure of electronic protected health information (ePHI) of 6,745 individuals. The ePHI included names, insurance numbers, diagnoses, medical histories, dates of birth, telephone numbers, and social security numbers. Upon discovery of the breach, the CE shut down all computer and email systems to prevent unauthorized access to its network and core files. In addition, the CE decommissioned the previously used server, deactivated the network router, disabled network access to ePHI, and discontinued the previously utilized backup. As a result of OCR's investigation, the CE deployed a new real-time firewall and intrusion detection system and implemented new measures for software management. In addition, the CE installed a new network server, deployed a new router with security subscription to actively monitor internal network traffic and external threat patterns, and implemented a centralized antivirus software system. 2011-11-15 2011-12-14 +Memorial Healthcare System FL 9497 Other Other 2014-01-23 2011-08-01 2012-02-12 +Roy E. Gondo, M.D. WA 2100 Theft Desktop Computer, Electronic Medical Record 2014-01-23 2012-02-21 +DRD Management, Inc. D/B/A DRD Knoxville Medical Clinic - Central TX 1000 Improper Disposal Paper 2014-01-23 2012-02-16 +Emory Healthcare GA 315000 Unknown, Other Other 2014-01-23 2012-02-07 2012-02-20 +Rex Smith, DPM -Rex Smith Podiatry OR 20915 Theft Desktop Computer 2014-01-23 2012-02-19 +Desert AIDS Project CA 4400 Theft Desktop Computer 2014-01-23 2012-04-12 +University of Arkansas for Medical Sciences AR 7121 Unauthorized Access/Disclosure Other 2014-01-23 2012-02-15 +TLC DENTAL DANIA, LLC FL 750 Theft Paper 2014-02-20 2012-04-23 +South Carolina Department of Health and Human Services SC 228435 Unauthorized Access/Disclosure E-mail 2014-01-23 2012-01-31 2012-04-02 +Oregon Health Authority OR 550 Theft Paper 2014-04-23 2012-04-13 +SHIELDS For Families CA 961 Theft Network Server 2014-01-23 2012-02-27 +Safe Ride Services, Inc AZ 42000 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2011-08-31 +IntraCare North Hospital TX 750 Theft Paper 2014-01-23 2011-03-15 2011-08-18 +Oakland Vision Services, PC MI 3000 Hacking/IT Incident Network Server 2014-03-24 2012-04-09 +Stephen Haggard, DPM Podiatry WA 1597 Theft Network Server 2014-01-23 2012-03-04 +Baptist Health System AL 1655 Improper Disposal Paper 2014-01-23 2012-03-08 +University of Houston for UH College of Optometry TX 7000 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2012-02-22 2012-02-23 +Rite Aid Store 1343 WV 2905 Theft Paper 2014-03-24 2012-03-26 +Iowa Department of Human Services IA 3000 Improper Disposal Paper 2014-01-23 2012-02-06 2012-03-14 +Hogan Services Inc. Health Care Premium Plan MO 1134 Unauthorized Access/Disclosure E-mail 2014-01-23 2012-03-30 +Family HealthServices Minnesota, P.A. MN 4000 Theft Laptop 2014-06-10 2012-03-30 +St. Mary Medical Center CA 3900 Loss Other Portable Electronic Device 2014-01-23 2012-05-07 +Fairview Health Services MN Accretive Health 623 Theft Laptop 2014-03-24 2011-07-25 +Our Lady of the Lake Regional Medical Center LA 17000 Theft, Loss Laptop 2014-01-23 2012-03-16 +UnitedHealth Group health plan single affiliated covered entity MN 19100 Unauthorized Access/Disclosure Other 2014-01-23 2011-06-28 2011-12-12 +West Dermatology CA 1900 Theft Other 2014-01-23 2012-04-21 2012-04-22 +Duke University Health System NC 591 Unauthorized Access/Disclosure Other 2014-01-23 2004-04-21 2012-02-16 +Luz Colon, DPM Podiatry FL 1137 Theft, Loss Laptop 2014-01-23 2012-03-20 +Ameritas Life Insurance Corp. NE 3000 Theft Laptop 2014-01-23 2012-03-21 +Children's Hospital Boston MA 2159 Theft Laptop 2014-01-23 2012-03-25 +Upper Valley Medical Center OH Data Image, Inc. 15000 Unauthorized Access/Disclosure Other 2014-01-23 2010-10-01 2012-03-21 +Physician's Automated Laboratory CA 745 Theft Paper 2014-01-23 2012-03-23 2012-03-26 +Phoebe Putney Memorial Hospital, Inc. GA 12937 Theft Electronic Medical Record, Paper 2014-02-20 2010-07-26 2012-03-29 +Independence Physical Therapy CT 925 Theft Desktop Computer 2014-01-23 2011-08-01 +Titus Regional Medical Center TX 5700 Loss, Unknown Laptop 2014-01-23 2012-03-27 +Titus Regional Medical Center TX 500 Theft Other 2014-01-23 2012-03-29 +Lutheran Community Services Northwest WA 756 Theft Desktop Computer, Other Portable Electronic Device 2014-01-23 2012-03-29 2012-03-30 +Volunteer State Health Plan, Inc. TN 1102 Loss Paper 2014-01-23 2012-03-16 2012-04-20 +Charlie Norwood VA Medical Center GA 824 Loss Other Portable Electronic Device 2014-01-23 2012-03-30 +Mid America Health, Inc. IN PrevMED 1444 Theft Laptop 2014-01-23 2012-04-06 +Metcare of Florida, Inc. FL 2557 Theft Other Portable Electronic Device 2014-01-23 2012-05-01 2012-05-02 +Robert Witham, MD, FACP OR 11136 Theft Desktop Computer 2014-01-23 2012-04-16 +Memorial Sloan-Kettering Cancer Center NY 568 Theft E-mail, Other 2014-06-03 The covered entity's (CE) staff member disclosed an unencrypted Microsoft Excel graph to a non-covered entity physician who re-disclosed it to a medical education organization to be used in a presentation. In addition, the medical education organization posted the presentation slides on its website. The graph contained the protected health information (PHI) of 569 individuals and included names, telephone numbers, social security numbers, ages, cities and states of residence, medical record numbers, and clinical information. Upon discovery of the breach, the CE ensured that the information was removed from the website and deleted, sanctioned the workforce member responsible, and retrained its workforce on the use of a data loss prevention tool and the risks of embedded PHI. As a result of OCR's investigation, the CE provided OCR with evidence of its technical safeguards and security awareness initiatives and provided assurance that it implemented the corrective action listed above. 2009-08-13 2012-04-12 +Gessler Clinic, P.A. FL 1409 Theft Paper 2014-01-23 2012-05-03 2012-05-04 +University of Kentucky HealthCare KY 4490 Theft Laptop 2014-01-23 2012-05-01 +Wolf & Yun KY 824 Theft Laptop 2014-01-23 2012-04-24 +Karen Kietzman MT 708 Theft Laptop, Other Portable Electronic Device 2014-03-21 2012-04-22 +Bruce G. Peller, DMD, PA NC 9953 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2012-04-22 +Sharon L. Rogers, Ph.D., ABPP TX 585 Theft Laptop 2014-01-23 2012-06-16 +Health Texas Provider Network - Cardiovascular Consultants of North Texas TX 2462 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2012-03-16 2012-05-11 +SwedishAmerican Health System IL 1500 Theft Paper 2014-03-24 2012-05-31 +River Arch Dental CA Patterson Dental, Inc. 2533 Loss, Unauthorized Access/Disclosure, Unknown Other Portable Electronic Device 2014-01-23 2012-05-12 +Hamner Square Dental CA Patterson Dental, Inc 1112 Theft, Loss, Unauthorized Access/Disclosure, Unknown Other Portable Electronic Device 2014-01-23 2012-05-12 +Visiting Nurse Services of Iowa IA 1298 Theft Paper 2014-01-23 2012-05-27 +Molalla Family Dental OR 4354 Unauthorized Access/Disclosure, Hacking/IT Incident, Other Network Server 2014-01-23 2012-05-17 +Pamlico Medical Equipment LLC NC 2917 Loss Other Portable Electronic Device 2014-01-23 2012-05-16 +Beth Israel Deaconess Medical Center MA 3900 Theft Laptop 2014-01-23 2012-05-22 +NYU School of Medicine Faculty Group Practice NY 8488 Theft Desktop Computer 2014-01-23 2012-05-22 +Adult & Child Center, Inc. IN Choices, Inc. 550 Hacking/IT Incident Other 2014-01-23 2012-05-10 +The Surgeons of Lake County, LLC IL 7067 Other Network Server 2014-01-23 2012-06-22 2012-06-25 +Kindred Healthcare Inc d/b/a Kindred Transitional Care and Rehabilitation-Sellersburg IN 1504 Theft Other 2014-01-23 2012-06-01 2012-06-04 +Jeffrey Paul Edelstein M.D. AZ 4800 Theft Network Server 2014-01-23 2012-05-28 +Northwestern Memorial Hospital IL 4211 Theft Laptop, Other Portable Electronic Device 2014-01-23 2012-06-11 +Walgreen Co. IL 1240 Theft Paper 2014-01-23 2012-07-05 +VNA HealthCare CT EMC 7461 Theft Laptop 2014-02-19 2012-06-25 +Hartford Hospital CT EMC 2097 Theft Laptop 2014-04-23 2012-06-25 +Diversified Support Services IN Choices, Inc. 505 Hacking/IT Incident Other 2014-01-23 2012-05-10 +Oregon Health & Science University OR 702 Theft Other 2014-01-23 2012-07-04 +Stanford Hospital & Clinics and School of Medicine CA 2300 Theft Desktop Computer 2014-01-23 2012-07-15 2012-07-16 +Midtown Mental Health Center IN CHOICES, Inc 890 Hacking/IT Incident Other 2014-01-23 2012-05-10 +Harris County Hospital District TX 2875 Theft Electronic Medical Record, Paper 2014-04-23 2008-04-14 2011-02-28 +Howard University Hospital DC Siemens Medical Solutions, USA 66601 Theft Laptop 2014-01-23 2012-01-25 +TEMPLE COMMUNITY HOSPITAL CA 603 Theft Desktop Computer 2014-01-23 2012-07-03 +Memorial Healthcare System FL 105646 Theft Electronic Medical Record 2014-01-23 2011-01-01 2012-07-05 +Liberty Resources, Inc. PA 3183 Theft Laptop 2014-06-24 "An employee's personal laptop computer that contained the unencrypted electronic protected health information (ePHI) of 3,183 individuals was stolen from his vehicle. The ePHI involved in the breach included consumer names, identification numbers, diagnosis codes, base service unit numbers, service start and end dates, service names, procedure codes, service location identifiers, units authorized, units utilized, units cost, total authorization amounts, total utilized amounts, authorization dates, funding sources, provider names, and master provider index numbers. The CE timely notified all affected individuals, the media, and HHS, and offered assistance to consumers who wished to place fraud alerts on their consumer credit files. Following the breach, the CE created and implemented a new policy and procedure to improve safeguards. This policy prohibits downloading any PHI to a home computer or portable device, prohibits forwarding emails containing PHI to a personal account, cloud service, or unauthorized user, and requires full-disk encryption of agency laptops. OCR obtained assurances that the CE implemented the corrective action listed above. + + + + + +" 2012-08-04 +The University of Texas MD Anderson Cancer Center TX 2264 Loss Other Portable Electronic Device 2014-01-23 2012-07-13 +Central States Southeast and Siouthwest Areas Health & Welfare Fund IL 754 Unauthorized Access/Disclosure, Other Paper 2014-01-23 2012-07-31 +LANA MEDICAL CARE FL 500 Theft Laptop 2014-01-23 2012-08-18 +Cancer Care Group, P.C. IN 55000 Theft Other Portable Electronic Device 2014-03-24 2012-07-19 +Tricounty Behavioral Health Clinic GA 4000 Theft Laptop 2014-01-23 2012-08-26 +Sierra Plastic Surgery NV 800 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2011-08-19 2011-09-20 +Charlotte Clark-Neitzel, MD WA 942 Theft Laptop 2014-01-23 2012-07-24 +University of Miami FL 64846 Unauthorized Access/Disclosure, Other Paper 2014-01-23 2012-07-18 +University of New Mexico Health Sciences Center NM 2365 Hacking/IT Incident Network Server 2014-01-23 2012-05-21 +Valley Plastic Surgery, P.C. VA 4873 Theft Other Portable Electronic Device 2014-03-24 2012-07-15 +Colon & Digestive Health Specialists AR Ecco Health, LLC 5713 Loss Other Portable Electronic Device 2014-01-23 2012-07-16 +BHcare, Inc CT 5827 Theft Laptop, Other Portable Electronic Device 2014-02-19 2012-07-19 +The Feinstein Institute for Medical Research NY 13000 Theft Laptop 2014-01-23 2012-09-02 +St. Therese Medical Group, Inc CA 3031 Theft Desktop Computer 2014-01-23 2012-07-22 +Cabinet for Health and Family Services, Department for Community Based Services (Protection and Permanency) KY 2500 Unauthorized Access/Disclosure E-mail 2014-01-23 2012-07-20 +Litton & Giddings Radiological Associates, P.C. MO PST Services, Inc 13074 Improper Disposal Paper 2014-01-23 2012-07-31 2012-08-02 +Apria Healthcare, Inc. CA 65700 Theft Laptop 2014-01-23 2012-06-14 +Alexander J. Tikhtman, M.D. KY 2376 Loss Other Portable Electronic Device 2014-01-23 2012-08-15 +Gulf Coast Health Care Services Inc FL 13000 Theft, Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-01-23 2012-08-17 +Blount Memorial Hospital, Inc TN 27799 Theft Laptop 2014-01-23 2012-08-25 +Alere Home Monitoring, Inc CA 116506 Theft Laptop 2014-01-23 2012-09-23 +Coastal home Respiratory, LLP GA 3440 Theft Other 2014-01-23 2012-10-04 + Philip P Corneliuson, DDS, INC. CA 980 Theft Desktop Computer 2014-01-23 2012-09-15 +First Step Counseling, Inc. NJ 638 Theft Paper 2014-06-03 Two of the covered entity's (CE) employees photocopied documents containing 638 patients' protected health information (PHI) and disclosed the documents to their attorney. The PHI included names, insurance numbers, diagnoses, dates of birth, telephone numbers, and social security numbers. Upon discovery of the breach, the CE hired attorneys to seek immediate return of all photocopies that contained the PHI. The CE provided breach notification to the affected individuals, HHS and the media. As a result of OCR's investigation, the CE transferred to an electronic billing system that is password protected and secured patient files with a lock. Further, the front desk has been positioned by a protective window and policies have been implemented to prevent patients from standing beside the reception desk. The CE also reviewed and revised its consent forms and retrained all staff. 2011-05-01 2011-08-05 +Logan Community Resources, Inc. IN 2900 Hacking/IT Incident Network Server 2014-01-23 2012-08-24 +David DiGiallorenzo, D.M.D. PA 2600 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server, Electronic Medical Record 2014-01-23 2012-09-17 +CVS Caremark RI 955 Theft Paper 2014-01-23 2012-08-13 +Memorial Hospital OH 500 Improper Disposal Paper 2014-03-24 2012-08-29 +SURGICAL ASSOCIATES OF UTICA, PC NY QUANTERION SOLUTIONS INC 1017 Theft Network Server 2014-06-20 "An unencrypted thumb drive that contained the electronic protected health information (ePHI) of 1,017 individuals was stolen by an employee of the covered entity's (CE) business associate (BA), Quanterion Solutions, Inc. The ePHI included names, addresses, dates of birth, driver's license numbers, social security numbers, claims information, clinical information, diagnosis/conditions, lab results, treatment information, and medications. Upon discovery of the breach, the CE, Surgical Associates of Utica, PC, filed a police report and the employee was arrested. The CE provided breach notification to HHS, the media, and affected individuals and provided credit monitoring services for these individuals. As a result of OCR's investigation, the CE executed a BA agreement. + + + +" 2012-09-18 +Illinois Department of Healthcare and Family Services IL University of Illinois, College of Nursing 508 Theft Paper 2014-03-24 2012-08-31 +Miami Beach Healthcare Group Ltd. dba Aventura Hospital and Medical Center FL 2560 Theft Electronic Medical Record 2014-01-23 2012-01-01 2012-09-12 +WYATT DENTAL GROUP, LLC LA 10271 Theft, Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2011-11-04 2012-04-15 +Women & Infants Hospital of Rhode Island RI 14004 Loss Other 2014-01-23 2012-09-13 +Memorial Health System CO 6262 Loss Paper 2014-01-23 2012-05-01 +CHRISTUS St. John Hospital TX 5748 Loss Other Portable Electronic Device 2014-01-23 2012-09-25 +L.A. Care Health Plan CA 18000 Other Other 2014-01-23 2012-09-17 2012-09-20 +Hawaii State Department of Health, Adult Mental Health Division HI 674 Hacking/IT Incident Desktop Computer 2014-01-23 2012-09-25 +Soundental Associates, PC CT 14511 Theft Other Portable Electronic Device 2014-02-19 2012-09-24 +Original Medicine Acupuncture & Wellness, LLC NM 540 Theft Laptop 2014-01-23 2012-09-07 2012-09-09 +Brigham and Women's Hospital MA 615 Theft Desktop Computer 2014-01-23 2012-10-16 +St. Francis Health Network, aka Franciscan Alliance ACO IN Advantage Health Solutions, Inc. 2575 Other Other 2014-01-23 2012-10-19 +James M. McGee, D.M.D., P.C. GA 1306 Theft Paper 2014-01-23 2012-09-19 2012-09-26 +Robbins Eye Center PC CT 1749 Theft Desktop Computer 2014-01-23 2012-10-07 +Advanced Data Processing, Inc. FL 10000 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +Cuyahoga County Board of Developmental Disabilities OH 613 Theft Laptop 2014-03-24 2012-11-02 +Okaloosa County Public Safety FL Advanced Data Processing, Inc. 715 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +City of Covington Kentucky Fire Department KY Advanced Data Processing Inc 1548 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +Northern Trust IL Blue Cross Blue Shield 500 Unauthorized Access/Disclosure Network Server 2014-03-24 2012-09-13 +Vidant Pungo Hospital NC 1100 Improper Disposal Paper 2014-01-23 2012-10-04 +County of San Bernardino Department of Public Heatlh CA 1370 Unauthorized Access/Disclosure Paper 2014-01-23 2012-09-28 2012-09-30 +City of Overland Park Fire Department FL Advanced Data Processing, Inc. 911 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +Sumner County Emergency Medical Services TN Advanced Data Processing, Inc 774 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +City of El Centro Fire Department CA ADPI-West 1500 Theft, Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2012-10-01 +Landmark Medical Center RI 683 Theft Laptop 2014-01-23 2012-10-01 +City of Atlanta/ Atlanta Fire Rescue Department GA Advanced Data Processing Inc. 908 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +University of Virginia Medical Center VA 1846 Loss Other Portable Electronic Device 2014-02-14 2012-10-05 +Osceola County EMS FL Advanced Data Processing Inc 949 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +Carolinas Medical Center - Randolph NC 5600 Hacking/IT Incident E-mail 2014-01-23 2012-03-11 2012-10-08 +Coastal Behavioral Healthcare, Inc. FL 4907 Theft Paper 2014-01-23 2011-04-11 +CCS Medical, Inc. TX 6601 Unauthorized Access/Disclosure Network Server, Other 2014-01-23 2012-05-01 2012-09-21 +City of Gloucester, Fire Department MA Advanced Data Processing, Inc. 1286 Theft Desktop Computer 2014-01-23 2012-06-15 2012-10-01 +Columbia University Medical Center and NewYork-Presbyterian Hospital NY 4929 Theft Desktop Computer 2014-01-23 2012-10-12 2012-10-15 +Baptist Health System AR Health Advantage 811 Other Paper 2014-01-23 2012-10-13 2012-10-27 +DFA, Employee Benefits Division AR Health Advantage 7039 Other Paper 2014-01-23 2012-10-13 2012-10-27 +Health Advantage AR 2863 Other Paper 2014-01-23 2012-10-13 2012-10-27 +University of Michigan Health System MI Omnicell, Inc. 3999 Theft Laptop 2014-01-23 2012-11-14 +Westerville Dental Center OH 850 Theft Laptop, Network Server 2014-01-23 2012-12-02 +OHP PHSP, Inc. NY HealthPlus, Amerigroup 28187 Unauthorized Access/Disclosure Other 2014-01-23 2012-08-31 2012-09-21 +Center for Orthopedic Research and Education, Inc. AZ 35488 Theft Paper 2014-04-23 2012-10-20 2012-10-21 +Calif. Dept. of Health Care Services (DHCS) CA 2643 Unauthorized Access/Disclosure Other 2014-01-23 2012-12-10 2012-12-18 +Richard Switzer MD PC MI 4100 Other Laptop 2014-03-24 2011-11-29 +Gibson General Hospital IN 28893 Theft Laptop 2014-03-24 2012-11-27 +Sovereign Medical Group, LLC NJ 27800 Theft, Hacking/IT Incident Network Server 2014-01-23 2012-10-10 +Cabinet for Health & Family Services, Department of Medicaid Services KY HP Enterprise Services 1090 Hacking/IT Incident Laptop 2014-01-23 2012-11-15 +Harbor Medical Associates, P.C. MA Clearpoint Design, Inc. 4343 Hacking/IT Incident Network Server 2014-01-23 2012-10-18 2012-11-04 +Sentara Healthcare VA Omnicell, Inc. 56820 Theft Laptop 2014-02-14 2012-11-14 +St. Mark's Medical Center TX 2988 Hacking/IT Incident Desktop Computer 2014-01-23 2012-05-21 +Group Health Incorporated NY 1771 Theft Paper 2014-06-20 "OCR opened an investigation of the covered entity (CE), Group Health Insurance, after it reported that postcard reminders were sent to 1,771 subscribers. The protected health information (PHI) involved included social security numbers within a series of other numbers inscribed on the outside of the postcard. The CE provided breach notification to HHS, the media, and affected individuals, and posted substitute notice on its website. Upon discovery of the breach, the CE suspended its mailing in order to verify subscriber information to ensure pending and completed projects did not contain social security numbers. As a result of OCR's investigation, the CE modified its mailing procedures to prevent similar disclosures from recurring in the future and retrained staff on its modified mailing procedure. The CE provided affected individuals with a free one year subscription for credit monitoring. + + + +" 2012-11-13 +Calvin Schuster,MD CA 532 Theft Desktop Computer 2014-01-23 2012-11-04 +Granite Medical Group, Inc. MA Clearpoint Design, Inc. 4125 Hacking/IT Incident Network Server 2014-02-19 2010-01-02 2012-11-15 +University of Nevada School of Medicine NV 1483 Improper Disposal Paper 2014-01-23 2012-10-11 +Dimensions Healthcare System MD WorkflowOne 635 Unauthorized Access/Disclosure Paper 2014-03-25 2012-11-16 +SilverScript Insurance Company AZ 852 Unauthorized Access/Disclosure Paper 2014-01-23 2012-10-31 +South Jersey Hospital Inc. NJ Omnicell Inc. 8555 Theft Laptop 2014-01-23 2012-11-14 +Child & Family Psychological Services, Inc. MA Clearpoint Design, Inc. 7250 Hacking/IT Incident Network Server 2014-01-23 2012-10-18 2012-10-29 +Pousson Family Dentistry LA 1400 Theft Laptop 2014-01-23 2012-12-03 +South Shore Medical Center MA Clearpoint Design, Inc. 4100 Hacking/IT Incident Network Server 2014-01-23 2007-01-01 2012-11-15 +Lee D. Pollan, DMD, PC NY 19178 Theft Laptop 2014-05-28 OCR opened an investigation of the covered entity (CE) after it reported an unencrypted laptop was stolen that contained the electronic protected health information (ePHI) of 19,178 individuals. The ePHI included names, addresses, zip codes, dates of birth, social security numbers, claims information, and diagnosis codes. Upon discovery of the breach, the CE filed a police report to recover the stolen items. As a result of OCR's investigation, the CE encrypted the backup drive of the contents of the laptop computer. The CE also trained all staff on the use of encryption to safeguard data on personal computers and mobile devices. 2012-11-06 2012-11-15 +Washington University School of Medicine MO 1105 Theft Laptop 2014-01-23 2012-11-28 +Riderwood Village MD 3230 Theft Laptop 2014-01-23 2012-11-18 +WAYNE MEMORIAL HOSPITAL PA 1184 Loss Other 2014-03-24 2012-12-03 +Baptist Health System TX 678 Unauthorized Access/Disclosure Electronic Medical Record 2014-03-13 2011-08-14 +Baillie Lumber Co. Group Health Plan NY BlueCross BlueShield of Western New York 725 Theft Paper 2014-06-20 OCR opened an investigation of the covered entity (CE), Baillie Lumber Co. Group Health Plan, after it reported its business associate (BA), Blue Cross Blue Shield, mailed a monthly premium notice with invoices that contained the protected health information (PHI) of 725 individuals which was never received by the CE. The PHI included names, member identification numbers, and social security numbers. The CE provided breach notification to HHS and affected individuals. Upon discovery of the breach, the BA contacted the U.S. Post Office to inquire about the package that contained the invoices that the CE never received. As a result of OCR's investigation, the BA revised its invoice process and removed social security numbers and member identification numbers from its invoices. The BA also improved safeguards by changing its mailing procedures to send invoices to the CE via secure email. The breach involved a BA and occurred prior to the September 23, 2013, compliance date. OCR verified that the CE had a proper BA agreement in place that restricted the BA's use and disclosure of PHI and required the BA to safeguard all PHI. 2012-11-27 +The University of Texas MD Anderson Cancer Center TX 29021 Theft Laptop 2014-01-23 2012-04-30 +Western Wisconsin Medical Association, S.C. - River Falls Medical Clinics WI 2400 Theft Paper 2014-03-24 2012-05-30 2012-08-31 +Boy Scouts of America Employee Benefit Plan TX RR Donnelley (a sub-BA for UnitedHealth Group) 8911 Theft Desktop Computer 2014-01-23 2012-09-15 2012-11-30 +Kmart Corporation IL Kmart Pharmacy #7623 16988 Improper Disposal Paper 2014-02-12 2013-01-02 +Community Services NW AL 2400 Theft Desktop Computer 2014-04-23 2012-12-06 +American HomePatient Inc. TN LifeGas 1103 Theft Laptop 2014-01-23 2012-10-11 +Yadkinville Chiropractic DCPA NC Yadkinville Chiropractic DCPA 1000 Theft Desktop Computer 2014-02-12 2013-02-01 +Intervention Services, Inc. FL 1200 Theft Laptop 2014-01-23 2013-01-19 +West Georgia Ambulance GA 500 Loss Laptop 2014-01-23 2012-12-13 +Center for Pain Management, LLC MD 5822 Theft Laptop 2014-01-23 2013-01-22 +Multiple Health Plans CA Coast Healthcare Management, LLC 1368 Theft, Other Paper 2014-01-23 2013-12-07 +Froedtert Health WI 43549 Unauthorized Access/Disclosure Other 2014-03-24 2012-10-27 2012-12-13 +Jackson Health System FL 566 Other Paper 2014-01-23 2011-05-26 2012-02-18 +Riderwood Village MD 5270 Theft Laptop 2014-01-23 2012-11-18 +Kindred Healthcare, Inc. d/b/a Kindred Transitional Care and Rehabilitation - Marl MA 716 Theft Other Portable Electronic Device 2014-01-23 2012-12-15 2012-12-17 +HomeCare of Mid-Missouri, Inc. MO 4027 Theft Laptop 2014-01-23 2012-12-14 +Heyman HospiceCare at Floyd GA 1819 Theft Laptop 2014-01-23 2013-01-04 +Agency for Health Care Administration FL DentaQuest of Florida, Inc. 1892 Unauthorized Access/Disclosure Paper 2014-01-23 2012-11-01 2012-12-20 +ABQ HealthPartners NM 778 Theft Laptop 2014-01-23 2012-12-20 +Terrell County Health Department GA 18000 Unauthorized Access/Disclosure Network Server 2014-01-23 2012-01-09 2012-04-17 +Florida Healthy Kids Corporation FL DentaQuest of Florida, LLC 3667 Unauthorized Access/Disclosure Paper 2014-01-23 2012-11-01 2012-12-20 +Stronghold Counseling Services Inc SD 8500 Theft Desktop Computer 2014-01-23 2012-12-24 +Arizona Oncology AZ 501 Theft Laptop 2014-01-23 2012-11-21 +Crescent Health Inc. - a Walgreens Company CA 109000 Theft Desktop Computer 2014-01-23 2012-12-28 +County of San Bernardino, Department of Behavioral Health CA 686 Theft Paper 2014-01-23 2013-01-12 +WOMENS HEALTH ENTERPRISE, INC. GA 3000 Theft Laptop 2014-01-23 2013-01-02 +The Brookdale University Hospital and Medical Center NY Standard Register 2261 Theft Paper 2014-06-20 OCR opened an investigation of the covered entity (CE), The Brookdale University Hospital and Medical Center, after it reported its business associate (BA), Standard Register, inadvertently mailed statements to 2,261 individuals using another affiliated CE's envelopes. The protected health information (PHI) included names, addresses and financial information. OCR provided technical assistance to the CE regarding safeguarding PHI. 2012-08-11 +The Brookdale University Hospital and Medical Center NY Health Plus Amerigroup 28187 Theft Other Portable Electronic Device 2014-06-20 The covered entity's (CE) business associate (BA), Health Plus Amerigroup, mailed an unencrypted compact disk that contained the electronic protected health information (ePHI) of 28,187 individuals to the CE, The Brookdale University Hospital and Medical Center. OCR closed this breach report and consolidated into an existing breach report filed by OHP PHSP, Inc. regarding the same issues. 2012-09-21 +Ultra Stores, Inc. IL Plexus Group 500 Unauthorized Access/Disclosure Other 2014-03-24 2012-09-13 +South Miami Hospital FL 834 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2011-06-01 +Lancaster General Medical Group PA 527 Theft Paper 2014-01-23 2013-02-05 +Maine Medical Center ME 1920 Other E-mail 2014-02-12 2013-02-27 +State of California, Dept. of Developmental Services CA North Los Angeles County Regional Center 18162 Theft Laptop 2014-01-23 2012-11-10 +Utah Department of Health UT Goold Health System (Goold) 6332 Loss Other Portable Electronic Device 2014-01-23 2013-01-10 2013-01-11 +Sports Rehabilitation Consultants OH 1200 Theft Desktop Computer 2014-02-12 2013-02-01 +University of Connecticut Health Center CT 1382 Unauthorized Access/Disclosure Network Server 2014-01-23 2010-06-07 2012-12-07 +United HomeCare Services, Inc. FL 12299 Theft Laptop 2014-01-23 2013-01-08 +United Home Care Services of Southwest Florida< LLC FL United HomeCare Services, Inc. 1318 Theft Laptop 2014-01-23 2013-01-08 +catoctin Dental/Richard B. Love, DDS, PA MD Patterson Dental Supply/Patterson Companies 6400 Hacking/IT Incident Network Server 2014-01-23 2013-01-03 +Empire Blue Cross Blue Shield IN Connextions c/o Empire BCBS 2608 Theft, Unauthorized Access/Disclosure Network Server 2014-01-23 2011-11-01 2012-10-01 +Anthem Blue Cross Blue Shield (OH) IN Connextions c/o Anthem BCBS 1678 Theft, Unauthorized Access/Disclosure Network Server 2014-01-23 2011-11-01 2012-10-01 +Anthem Blue Cross Blue Shield (IN) IN Connextions c/o Anthem BCBS 528 Theft, Unauthorized Access/Disclosure Network Server 2014-01-23 2011-11-01 2012-10-01 +Mount Sinai Medical Center FL 628 Theft Desktop Computer, Paper 2014-01-23 2012-10-01 2013-02-18 +Thomas L. Davis, Jr. DDS OR 3269 Theft Desktop Computer, Electronic Medical Record 2014-01-23 2013-02-12 +HealthCare for Women, Inc. MA 8727 Hacking/IT Incident Network Server 2014-01-23 2013-01-18 2013-01-23 +University of Mississippi Medical Center MS 500 Loss Laptop 2014-01-23 2012-11-01 2013-01-19 +Granger Medical Clinic UT 2600 Theft, Loss, Other Paper 2014-02-12 2013-01-17 +Texas Tech Unversity Health Sciences Center TX 697 Unauthorized Access/Disclosure Paper 2014-01-23 2013-02-18 +Rite Aid #10217 RI 2082 Unknown, Other Paper 2014-02-12 2013-02-01 +WA Department of Social and Health Services WA Sunil Kakar, Psy.D. 629 Theft Laptop 2014-01-23 2013-02-04 +Carpenters Health & Welfare Trust Fund for California CA QuickRunner, Inc. (dba, RoadRunner Mailing Services) 2400 Unauthorized Access/Disclosure Paper 2014-01-23 2013-03-11 2013-03-12 +Shands Jacksonville Medical Center, Inc. FL 1025 Theft, Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2012-05-02 2012-06-22 +University of Florida FL 14519 Theft, Unauthorized Access/Disclosure, Other Network Server 2014-01-23 2009-03-01 2012-10-25 +Kmart Corporation IL 12542 Theft Electronic Medical Record 2014-02-12 2013-03-17 +GLENS FALLS HOSPITAL NY PORTAL HEALTHCARE SOLUTIONS LLC 2360 Theft Network Server 2014-06-03 The covered entity's (CE) business associate (BA) operated a server containing the electronic protected health information (ePHI) of 2,360 individuals that was vulnerable to access by unauthorized persons for over four months. The ePHI included transcribed doctors' notes, which may have included medical diagnoses, clinical laboratory results, diagnostic imaging reports, emergency department records, and medication administration. Upon discovery of the breach, the CE engaged a computer forensic expert to investigate the incident and terminated the BA agreement. As a result of OCR's investigation, the CE ensured that its BA secured the server, verified that the server was no longer accessible from the Internet, and required the BA to return or destroy all of the CE's ePHI. 2012-11-02 2013-03-14 +Hospice and Palliative Care Center of Alamance Caswell NC 5370 Theft, Unauthorized Access/Disclosure Laptop, Paper 2014-01-23 2013-02-24 +Texas Health Care, P.L.L.C. TX 554 Theft Paper 2014-01-23 2013-03-10 +Network Health Insurance Corporation WI TMG Health 3794 Unauthorized Access/Disclosure Paper 2014-03-24 2012-02-27 +Wm. Jennings Bryan Dorn VAMC SC 7405 Loss Laptop 2014-01-23 2013-02-11 +John J. Pershing VA Medical Center MO 589 Theft Paper 2014-06-20 "OCR opened an investigation of the covered entity (CE), John J. Pershing VA Medical Center, after the CE reported that its business associate (BA), Stress Laboratory, placed a box of unsecured protected health information (PHI) in an equipment storage room. The PHI included the names, social security numbers, diagnoses, and age of approximately 589 individuals. This breach incident involved a BA, and occurred prior to the September 23, 2013 compliance date. The BA employee involved in this matter separated from employment in 2012, and the BA was reorganized and has been incorporated into the CE. The CE provided breach notification to affected individuals, HHS, and the media. Substitute notification was provided through a posting on the CE's main website with a toll-free information number. The CE also offered one year of identity protection and credit monitoring services to affected individuals. As a result of this incident, the CE adopted a new policy that provides guidance to its staff regarding the handling of PHI. Additionally, the CE trained its employees on this new policy, and re-trained its employees on the Privacy, Security, and Breach Notification Rules. Finally, OCR obtained assurances that the CE implemented the corrective action listed above. + + + +" 2013-02-20 +Oregon Health & Science University OR 1076 Theft Laptop 2014-01-23 2013-02-22 +Schneck Medical Center IN 3131 Unauthorized Access/Disclosure Other 2014-02-12 2013-03-14 +The Guidance Center of Westchester NY 1416 Theft Desktop Computer 2014-01-23 2013-02-21 +Hope Hospice TX 818 Other E-mail 2014-01-23 2012-12-27 2013-02-22 +IHC Health Services, Inc. dba Intermountain Life Flight UT 857 Unauthorized Access/Disclosure Other 2014-02-12 2013-03-28 +Valley Mental Health UT 700 Theft Desktop Computer 2014-01-23 2013-02-27 +Delta Dental of Pennsylvania PA ZDI 14829 Loss Paper 2014-01-23 2013-03-20 +Raleigh Orthopaedic Clinic NC 17300 Theft, Improper Disposal, Unauthorized Access/Disclosure Paper 2014-01-23 2013-01-15 +Laboratory Corporation of America NC 1580 Theft Desktop Computer 2014-02-12 2013-03-15 +Arizona Counseling & Treatment Services, LLC AZ 3800 Theft Other Portable Electronic Device 2014-01-23 2013-03-18 2013-03-25 +Wood County Hospital OH 2500 Theft Other 2014-01-23 2013-03-19 +University of Rochester Medical Center & Affiliates NY 537 Loss Other Portable Electronic Device 2014-01-23 2013-02-15 +Orthopedics & Adult Reconstructive Surgery TX AssuranceMD f/k/a Harbor Group 22000 Loss Other Portable Electronic Device 2014-01-23 2013-03-01 2013-03-13 +El Centro Regional Medical Center CA Digital Archive Management 189489 Improper Disposal Paper 2014-01-23 2012-11-07 +Seattle - King County Department of Public Health WA 750 Improper Disposal Paper 2014-01-23 2013-03-07 +Regional Medical Center TN 1180 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-02-04 +Presbyterian Anesthesia Associates PA NC E-dreamz, Inc. 9988 Hacking/IT Incident Network Server 2014-01-23 2013-04-01 +Integrity Oncology, an office of Baptist Medical Group TN North Atlantic Telecom, Inc. 539 Other Desktop Computer 2014-01-23 2013-03-05 +Piedmont HealthCare, P.A. NC E-dreamz, Inc. 1924 Hacking/IT Incident Network Server 2014-01-23 2013-03-28 +Indiana University Health Arnett IN 10350 Theft Laptop 2014-01-23 2013-04-09 +Dent Neurologic Group, LLP NY 10000 Other E-mail 2014-01-23 2013-05-13 +City of Norwood OH 9577 Loss Laptop 2014-01-23 2013-04-14 2013-04-19 +Lutheran Social Services of South Central Pennsylvania PA 7803 Hacking/IT Incident Network Server 2014-01-23 2012-06-01 2013-03-07 +Comfort Dental Marion and Kokomo IN Just the Connection Inc 5388 Improper Disposal Other 2014-01-23 2013-03-14 2013-03-18 +Erskine Family Dentistry IN 2723 Hacking/IT Incident Desktop Computer 2014-02-12 2013-03-19 +Health Resources of Arkansas AR 1900 Theft, Unauthorized Access/Disclosure Other 2014-01-23 2013-04-14 +Various Health Plans AL SynerMed / Inland Valleys IPA 3164 Theft Laptop 2014-01-23 2013-04-14 2013-04-15 +Independence Care System NY 2434 Theft Laptop 2014-01-23 2013-05-07 +Sonoma Valley Hospital CA 1386 Other Other 2014-01-23 2013-02-14 +University of Florida FL 5875 Theft, Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2012-02-01 2013-04-11 +Community Support Services, Inc. OH 1167 Theft E-mail 2014-02-12 2013-03-20 2013-03-26 +UMASSAmherst MA 1670 Hacking/IT Incident Desktop Computer 2014-01-23 2012-10-22 +Palm Beach County Health Department FL 877 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2013-01-07 +Lucile Packard Children's Hospital CA 12900 Theft Laptop 2014-01-23 2013-05-08 +Fayetteville VAMC NC 1093 Improper Disposal Paper 2014-01-23 2013-04-17 +Lincoln County Health and Human Services/Lincoln Community Health Center OR 959 Unauthorized Access/Disclosure Paper 2014-01-23 2013-04-17 +Union Security Insurance Company MO 1127 Improper Disposal E-mail 2014-01-23 2013-05-17 +Gulf Breeze Family Eyecare, Inc FL 9626 Theft, Unauthorized Access/Disclosure Desktop Computer, Network Server, E-mail, Electronic Medical Record, Paper 2014-01-23 2013-03-08 2013-05-09 +Jacksonville Spine Center FL 5200 Unauthorized Access/Disclosure Paper 2014-01-23 2013-04-25 +Iowa Department of Human Services IA 7335 Loss, Unknown Other 2014-01-23 2013-04-30 +James A. Fosnaugh NE 2125 Loss Other Portable Electronic Device 2014-01-23 2013-05-01 2013-05-03 +Lone Star Circle of Care TX 1955 Theft Laptop 2014-01-23 2013-05-01 2013-05-02 +Aflac GA Alberto Gerardo Vazquez Rivera 679 Theft Laptop 2014-01-23 2013-05-09 +Indiana Family & Social Services Administration IN RCR Technology Corporation 187533 Other Paper 2014-01-23 2013-04-06 2013-05-21 +Northrop Grumman Retiree Health Plan VA CVS Caremark 4305 Theft Paper 2014-06-24 Business associate (BA) employees erroneously sent 4,305 health plan members' protected health information (PHI) to other plan members. The PHI involved in the breach included names and prescribed medication(s). The covered entity, Northrop Grumman Retiree Health Plan, provided breach notification to HHS, and the BA, CVS Caremark, provided breach notification to affected individuals and the media. Following the breach, the BA revised its quality control policies for targeted mailings and retrained employees involved in the breach to prevent similar incidents in the future. OCR obtained assurances that the BA implemented the breach notification and policy revisions listed above. 2013-05-20 +Health Net, Inc. CA 8331 Other Paper 2014-01-23 2013-04-01 2013-05-31 +South Florida Neurology Associates, P.A. FL 900 Theft Laptop 2014-01-23 2013-05-25 2013-05-30 +Samaritan Regional Health System OH 2203 Other Paper 2014-01-23 2013-05-29 +MED-EL Coproration NC 609 Other E-mail 2014-01-23 2013-06-25 +Sutter Health East Bay Region (Alta Bates Summit Medical Center; Sutter Delta Medical Center; Eden Medical Center) CA Nelson Family of Companies 4479 Unauthorized Access/Disclosure E-mail 2014-01-23 2011-03-01 +Illinois Department of Healthcare and Familiy Services IL Family Health Network 3133 Other Paper 2014-01-23 2013-05-08 +Delta Dental of Pennsylvania PA ZDI 4718 Loss Paper 2014-01-23 2013-05-13 +Medtronic, Inc. MN 2764 Loss Paper 2014-01-23 2013-03-28 2013-03-29 +Texas Health Harris Methodist Hospital Fort Worth TX Shred-it International Inc. 277014 Improper Disposal Other 2014-01-23 2013-05-11 +Long Beach Memorial Medical Center CA 2864 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2012-09-01 2013-07-01 +Hansen & Associates WY 2700 Theft Desktop Computer 2014-06-10 2013-05-21 2013-05-29 +Sheet Metal Local 36 Welfare Fund MO People Resource Corporation 4560 Unauthorized Access/Disclosure Other 2014-01-23 2012-08-01 2013-07-08 +Harris County TX 21000 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2005-08-15 2007-06-14 +San Jose Medical Supply Co., Inc. CA Jesle Kuizon 800 Theft, Unauthorized Access/Disclosure, Hacking/IT Incident Desktop Computer, Network Server 2014-01-23 2011-10-01 +GEO Care, LLC FL 710 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2013-04-16 +The Brookdale Hospital and Medical Center NY 2700 Loss Other Portable Electronic Device 2014-01-23 2013-05-24 +Louisiana State University Health Care Services Division LA 6994 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2011-12-01 +Oregon Health & Science University OR 1361 Unauthorized Access/Disclosure Other 2014-01-31 2011-01-01 2013-07-03 +Rocky Mountain Spine Clinic, P.C. CO 532 Theft, Unauthorized Access/Disclosure Network Server 2014-01-23 2013-06-11 +Vitreo-Retinal Medical Group, Inc. CA 1837 Theft Laptop 2014-01-23 2013-06-05 +Arkansas Department of Human Services AR Health Resources of Arkansas 1911 Theft Laptop 2014-02-12 2013-04-14 +Baylor All Saints Medical Center at Fort Worth TX 940 Unauthorized Access/Disclosure Other Portable Electronic Device 2014-02-12 2013-05-07 2013-06-06 +Cogent Healthcare, Inc. TN M2ComSys Inc. 32151 Unauthorized Access/Disclosure Network Server 2014-01-23 2013-05-05 2013-06-24 +Young Family Medicine Inc. OH 2045 Theft Laptop 2014-01-23 2013-06-12 +Hancock OB/GYN IN 1396 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2011-11-09 2013-06-17 +Colfax IN Anthem BCBS of GA 5497 Other Other 2014-02-12 2013-04-11 +Missouri Department of Social Services MO InfoCrossing, Inc. 1357 Unauthorized Access/Disclosure Paper 2014-01-23 2011-10-16 2013-06-07 +Foundations Recovery Network TN 5690 Theft Laptop 2014-01-23 2013-06-15 +California Correctional Health Care Services CA 1033 Other Paper 2014-01-23 2013-06-19 +North Texas Comprehensive Spine & Pain Center TX 3200 Theft, Loss Other Portable Electronic Device 2014-02-12 2013-06-16 +Minne-Tohe Health Center/Elbowoods Memorial Health Center ND 10000 Improper Disposal, Unauthorized Access/Disclosure Desktop Computer, Other 2014-01-23 2011-10-01 +Jackson Health System FL 1471 Other Paper 2014-01-23 2013-01-08 2013-01-10 +Advocate Health and Hospitals Corporation, d/b/a Advocate Medical Group IL 4029530 Theft Desktop Computer 2014-01-23 2013-07-15 +Summit Community Care Clinic, Inc. CO 921 Hacking/IT Incident Desktop Computer 2014-01-23 2013-07-22 +UT Physicians TX 596 Theft, Loss Laptop 2014-01-23 2013-07-22 2013-08-02 +Parkview Community Hospital Medical Center CA Cogent Healthcare, Inc. 32000 Other Network Server 2014-01-23 2013-05-05 2013-06-24 +Atlanta Center for Reproductive Medicine GA 654 Other E-mail 2014-01-23 2013-07-12 +St. Anthony's Physician Organization MO 2600 Theft Laptop, Other Portable Electronic Device 2014-01-23 2013-07-29 +Janna Benkelman LPC LLC CO 1500 Theft Laptop 2014-01-23 2013-08-01 +Olson & White Orthodontics MO 10000 Theft Desktop Computer, Network Server 2014-01-23 2013-07-22 +Kaiser Foundation Health Plan of the Northwest OR 647 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2013-03-15 +Hankyu Chung, M.D. CA 2182 Theft Laptop 2014-01-23 2013-06-17 +ICS Collection Service, Inc. on behalf of University of Chicago Physicians Group IL ICS Collection Service, Inc. 1290 Hacking/IT Incident Other 2014-01-23 2013-07-09 +ACO of Puerto Rico PR PHMHS 5000 Theft Network Server 2014-06-20 Upon request, a subcontractor (PHM Software Solutions) of the covered entity's (CE) business associate (BA), PHM Healthcare Solutions, modified a software application the CE was utilizing which led to the disclosure of electronic protected health information (ePHI) of 5,000 individuals on the Internet. The ePHI included names, gender, member identification numbers, dates of birth, and consent forms. The CE provided breach notification to HHS, the media, and affected individuals and posted substitute notice on its website. Upon discovery of the breach, the BA removed the software application and placed it offline. As a result of OCR's investigation, the CE had its BA to conduct a risk analysis and create a risk management plan to address any vulnerabilities identified in the risk analysis. The breach incident involved a BA and occurred prior to the September 23, 2013, compliance date. OCR provided technical assistance to assist the CE understand its obligations under the Privacy and Security Rules regarding BA agreements. 2013-03-05 2013-07-16 +NHC HealthCare, Oak Ridge TN 4268 Loss Other 2014-03-13 2013-05-10 +NHC HealthCare, Mauldin SC 4204 Improper Disposal Other 2014-03-13 2013-05-15 +Advocate Health and Hospitals Corporation d/b/a Advocate Medical Group IL Blackhawk Consulting Group 2029 Hacking/IT Incident Network Server 2014-02-12 2013-06-30 2013-08-15 +Dreyer Medical Clinic IL Blackhawk Consulting Group 998 Hacking/IT Incident Network Server 2014-01-23 2013-06-30 2013-08-15 +South Shore Physicians, PC NY 8000 Theft Network Server 2014-01-23 2006-01-01 2012-01-12 +Dermatology Associates of Tallahassee FL 916 Unknown Other 2014-01-23 2013-09-04 +Sierra View District Hospital CA 1009 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2013-07-01 2013-08-02 +Missouri Department of Social Services MO InfoCrossing, Inc. 25461 Unauthorized Access/Disclosure Paper 2014-02-12 2009-12-21 2013-06-07 +Holy Cross Hospital, Inc. FL 9900 Theft, Unauthorized Access/Disclosure Desktop Computer, Network Server 2014-01-23 2013-08-14 +Region Ten Community Services Board VA 10228 Hacking/IT Incident E-mail 2014-01-23 2013-07-29 +Comprehensive Podiatry LLC OH 1360 Theft Laptop 2014-01-23 2013-08-03 +Santa Clara Valley Medical Center CA 579 Theft Laptop 2014-01-23 2013-09-14 2013-09-15 +Sarah Benjamin, DPM - Littleton Podiatry CO Not Applicable 3512 Theft Laptop 2014-01-23 2013-08-27 +Carol L. Patrick, Ph.D. OH 517 Theft Network Server 2014-01-23 2013-08-08 2013-08-09 +HOPE Family Health TN 6932 Theft Laptop 2014-01-23 2013-08-04 +Paul G. Klein, DPM NJ 2500 Theft Laptop 2014-06-20 " + +OCR opened an investigation of the covered entity (CE), Paul G. Klein DPM, after it reported an encrypted and password protected laptop was stolen that contained the electronic protected health information (ePHI) of 2,500 individuals. The ePHI included names, addresses, dates of birth, social security numbers, diagnosis conditions, lab test results, medications, medical notes, and treatment plans. Upon discovery of the breach, the CE filed a police report to recover the stolen item. As a result of OCR's investigation, the CE provided confirmation that there was encryption software and multi-layered password protection software installed on the stolen laptop. OCR determined that the impermissible disclosure of ePHI did not constitute a breach under the Privacy Rule's breach notification rule and provided technical assistance to the CE regarding the requirements of the breach notification rule. + + + +" 2013-10-01 +UnityPoint Health Affiliated Covered Entity (\UnityPoint\) IA 1825 Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2013-02-01 2013-08-27 +TSYS Employee Health Plan GA Paragon Benefits, Inc. 5232 Theft E-mail 2014-01-23 2013-09-05 +University of California, San Francisco CA 3553 Theft Laptop, Paper 2014-01-23 2013-09-09 +Reconstructive Orthopaedic Associates II, P.C. d/b/a Rothman Institute PA 2350 Theft, Unauthorized Access/Disclosure Paper 2014-01-23 2013-03-18 2013-05-13 +Group Health Cooperative WA 1015 Other Paper 2014-01-23 2013-09-16 +Schuylkill Health System PA 2810 Theft Laptop 2014-01-23 2013-08-07 +CaroMont Medical Group NC 1310 Other E-mail 2014-01-23 2013-08-05 +Mount SInai Medical Center NY 1586 Improper Disposal Paper 2014-01-23 2013-08-06 +Memorial Hospital of Lafayette County WI Healthcare Management System 4330 Unauthorized Access/Disclosure Paper 2014-01-23 2013-08-03 +Saint Louis University MO 3100 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-07-25 +MUSC Physicians & MUHA SC BlackHawk 7120 Hacking/IT Incident Network Server 2014-02-12 2013-06-30 +Ferris State University - MI College of Optometry MI 3947 Hacking/IT Incident Network Server 2014-01-23 2011-12-01 +Access Counseling, LLC IN 566 Theft Laptop 2014-01-23 2013-08-23 +Rose Medical Center CO 606 Improper Disposal Paper 2014-01-23 2013-06-28 2013-07-16 +BriovaRx IL 1067 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-07-03 2013-07-11 +North Country Hospital and Health Center, Inc VT 550 Theft Laptop 2014-01-23 2013-09-18 +Hope Community Resources, Inc. AK 1556 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-08-19 +Broward Health Medical Center FL 960 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2012-10-01 2012-12-31 +Sentara Healthcare VA 3645 Theft Electronic Medical Record, Paper 2014-01-23 2012-10-01 2013-07-11 +Mount Sinai Medical Center NY 610 Loss Other Portable Electronic Device 2014-02-12 2013-08-01 +Texas Health Presbyterian Dallas Hospital TX 949 Theft Desktop Computer 2014-02-12 2013-08-22 +Seton Healthcare Family TX 5500 Theft Laptop 2014-01-23 2013-10-04 +BRONX-LEBANON HOSPITAL CENTER NY PROFESSIONAL TRANSCRIPTION SERVICES 10930 Unauthorized Access/Disclosure Network Server 2014-01-23 2009-09-23 +Martin Luther King Jr. Health Center, Inc. NY PROFESSIONAL TRANSCRIPTION SERVICES 37000 Unauthorized Access/Disclosure Network Server 2014-01-23 2009-09-23 +SSM St. Mary's Health Center MO Saint Louis University 1300 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-07-25 +Good Samaritan Hospital CA 3833 Theft Laptop 2014-01-23 2013-07-08 +SSM Health Care of Wisconsin DBA: St. Mary's Janesville Hospital WI 631 Theft Laptop 2014-01-23 2013-08-27 +AHMC Healthcare Inc. and affiliated Hospitals CA 729000 Theft Laptop 2014-01-23 2013-10-12 +Greater Dallas Orthopaedics, PLLC TX 5840 Theft Desktop Computer 2014-01-23 2013-08-30 +Spirit Home Health Care, Corp FL Spirit Home Health Care, Corp 603 Improper Disposal Paper 2014-01-23 2013-09-19 +Rotech Healthcare Inc. FL 10680 Unauthorized Access/Disclosure Laptop 2014-02-18 2010-11-26 2013-10-01 +Reimbursement Technologies, Inc. PA 2300 Unauthorized Access/Disclosure Network Server 2014-01-23 2013-05-01 2013-07-26 +Comprehensive Psychological Services LLC SC 3500 Theft Laptop 2014-01-23 2013-10-28 +Superior HealthPlan, Inc. TX 6284 Other Paper 2014-01-23 2013-10-04 +Genesis Rehabilitation Services PA 1167 Loss Other Portable Electronic Device 2014-01-23 2013-08-30 +Colorado Health & Wellness, Inc. CO 651 Theft, Unauthorized Access/Disclosure Electronic Medical Record 2014-01-23 2013-09-04 +Barnabas Health Medical Group NJ 1100 Theft Laptop 2014-01-23 2013-09-24 +DaVita, a division of DaVita HealthCare Partners Inc CO 11500 Theft, Other Laptop 2014-01-23 2013-09-06 +Blue Cross and Blue Shield of North Carolina NC 687 Unauthorized Access/Disclosure Paper 2014-01-23 2013-10-14 +North Carolina Department of Health and Human Services - Division of State Operated Health Care Facilities NC 1315 Unauthorized Access/Disclosure Other 2014-01-23 2013-08-13 +Puerto Rico Health Insurance Administration (PRHIA) PR Triple S Salud Inc. 13336 Unauthorized Access/Disclosure Paper 2014-01-23 2013-09-20 +Triple-S Salud PR 70189 Unauthorized Access/Disclosure Paper 2014-01-23 2013-09-20 +Associated Urologists of North Carolina NC 7300 Other Other 2014-01-23 2012-09-17 2013-09-17 +Kemmet Dental Design ND 2000 Theft, Other Paper 2014-01-23 2013-11-10 +Hospice of the Chesapeake MD 7606 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-08-09 +Scottsdale Dermatology, LTD AZ All Source Medical Management 1456 Theft Other 2014-01-23 2013-01-01 2013-10-04 +Memorial Sloan-Kettering Cancer Center NY 2279 Loss Other Portable Electronic Device 2014-02-18 2013-08-01 +Gerdau Ameristeel Health and Welfare Plan FL Health Fitness Corporation 3804 Theft Laptop 2014-02-18 2013-09-27 +Gerdau Macsteel Health and Welfare Plan MI Health Fitness Corporation 4837 Theft Laptop 2014-02-18 2013-09-27 +UHS-Pruitt Corporation GA 1300 Theft Laptop 2014-01-23 2013-09-26 +United Dynacare, LLC dba Dynacare Laboratories WI 9328 Theft Other Portable Electronic Device 2014-01-23 2013-10-22 +Redwood Memorial Hospital CA 1039 Loss Other Portable Electronic Device 2014-01-23 2013-11-06 +Kaiser Foundation Hospital- Orange County CA 49000 Loss Other Portable Electronic Device 2014-01-23 2013-09-25 +Jones Chiropractic and Maximum Health IN 1500 Theft Desktop Computer 2014-01-23 2013-10-13 +Ronald Schubert MD PLLC WA 950 Theft Laptop 2014-01-23 2013-11-22 +UPMC PA 1279 Unauthorized Access/Disclosure Electronic Medical Record 2014-02-18 2012-11-05 2013-11-06 +UW Medicine WA 76183 Hacking/IT Incident Desktop Computer 2014-02-18 2013-10-02 +City of Chicago IL 2080 Unauthorized Access/Disclosure Network Server 2014-01-23 2013-06-18 2013-10-07 +CIty of Joliet IL Quality Health Claims Consultants, LLC 1573 Unauthorized Access/Disclosure E-mail 2014-01-23 2013-10-08 +SIU HealthCare IL 1891 Theft, Loss Laptop 2014-01-23 2013-09-13 2013-10-15 +The Good Samaritan Health Center GA 5000 Other Desktop Computer 2014-01-23 2013-11-06 +UniHealth Source GA 4500 Theft Laptop 2014-01-23 2013-10-08 +Walgreen Co. IL 17350 Other Paper 2014-01-23 2013-09-18 2013-10-04 +Methodist Dallas Medical Center TX 44000 Unauthorized Access/Disclosure Other 2014-01-23 2005-09-01 2013-08-01 +Florida Digestive Health Specialists FL 4400 Unauthorized Access/Disclosure Desktop Computer 2014-01-23 2013-03-06 2013-09-09 +Northside Hospital, Inc. GA 4879 Loss Laptop 2014-01-23 2013-10-10 +Health Help, Inc. KY 535 Theft Other Portable Electronic Device 2014-01-23 2013-10-15 +L.A. Gay & Lesbian Center CA 59000 Hacking/IT Incident Network Server 2014-01-23 2013-09-17 2013-11-08 +Mosaic NE 3857 Other E-mail 2014-01-23 2013-10-11 +New Jersey Department of Human Services NJ Island Peer Review Organization 9642 Loss Other Portable Electronic Device 2014-01-23 2013-10-18 +Fairfax County, Virginia VA Molina Healthcare In 1499 Unauthorized Access/Disclosure Network Server 2014-01-23 2013-09-09 2013-10-03 +Wyoming Department of Health WY 11935 Unauthorized Access/Disclosure Network Server 2014-01-23 2013-10-16 +Shiloh Medical Clinic MT 1900 Unauthorized Access/Disclosure Desktop Computer, E-mail 2014-01-23 2013-11-08 +South Carolina Health Insurance Pool SC DeLoach & Williamson 3432 Theft Laptop 2014-01-23 2013-10-16 +Tennova Cardiology TN Colby DeHart 2777 Theft Laptop 2014-01-23 2013-10-21 +Delta Dental of Pennsylvania PA ZDI 1674 Loss Paper 2014-03-13 2013-10-16 +Molina Healthcare of Texas, Inc. TX 2826 Other Paper 2014-01-23 2013-10-01 +Rob Meaglia, DDS CA 1400 Theft Desktop Computer 2014-01-23 2013-12-16 +Jeff Spiegel MA 832 Unauthorized Access/Disclosure E-mail 2014-03-13 2013-11-25 +Tranquility Counseling Services NC 1683 Other Paper 2014-01-23 2013-11-01 +Florida Department of Health FL 2354 Unauthorized Access/Disclosure Desktop Computer 2014-03-05 2013-10-30 +New Mexico Oncology Hematology Consultants, LTD NM 12354 Theft Laptop 2014-01-23 2013-11-13 +Department of Health Care Policy & Financing CO Colorado Community Health Alliance (CCHA)/Physicians Health Partners 1918 Unauthorized Access/Disclosure E-mail 2014-02-21 2013-11-21 +Horizon Healthcare Services, Inc., doing business as Horizon Blue Cross Blue Shield of New Jersey, and its affiliates NJ 839711 Theft Laptop 2014-02-21 2013-11-01 +Phoebe Putney Memorial Hospital GA 6989 Loss Desktop Computer 2014-02-11 2013-11-05 +Coulee Medical Center WA 2500 Unauthorized Access/Disclosure Laptop, Network Server, E-mail 2014-02-11 2010-01-01 2013-11-30 +University of Pennsylvania Health System PA RevSpring, Inc. 3000 Other Paper 2014-02-11 2013-11-26 +North Carolina Department of Health and Human Services NC 48752 Unauthorized Access/Disclosure Other 2014-02-11 2013-12-30 +101 FAMILY MEDICAL GROUP CA Phreesia, Inc 2500 Theft Laptop 2014-02-11 2013-11-23 +Tri Lakes Medical Center MS 1489 Hacking/IT Incident Network Server 2014-02-11 2013-09-20 +VA Dept. of Medical Assistance Services VA Virginia Premier Health Plan (VPHP) 25513 Unauthorized Access/Disclosure, Other Paper 2014-02-11 2013-11-15 +Cook County Health & Hospitals System IL 22511 Other E-mail 2014-02-11 2013-11-12 +Southwest General Health Center OH 953 Unknown Other 2014-05-30 2013-04-13 2013-10-31 +Robert B. Neves, M.D., Inc CA 611 Theft Laptop 2014-01-24 2011-05-08 +Triple-S Salud, Inc. PR Triple-C, Inc. 398000 Theft Network Server 2014-02-18 2010-09-09 +Triple-S Salud, Inc. PR Triple-C, Inc. 8000 Theft, Unauthorized Access/Disclosure Network Server 2014-01-24 2008-10-03 +Urology Centers of Alabama PC and Urology Health Foundation AL Birmingham Printing and Publishing, Inc dba Paper Airplane 1085 Other Other 2014-06-03 2013-08-22 +Medical Mutual of Ohio OH 1420 Unauthorized Access/Disclosure Paper 2014-06-13 2013-10-16 +Unity Health Plans Insurance Corporation WI University of Wisconsin-Madison School of Pharmacy 41437 Loss Other Portable Electronic Device 2014-02-21 2013-12-12 +The University of Texas MD Anderson Cancer Center TX 3598 Loss Other Portable Electronic Device 2014-02-11 2013-12-02 +Beebe Medical Center DE 1883 Other Laptop 2014-02-21 2013-09-02 +St. Joseph Health System TX 405000 Hacking/IT Incident Network Server 2014-02-11 2013-12-16 +Min Yi, M.D. CA 4676 Theft Other Portable Electronic Device 2014-02-21 2013-05-28 +Easter Seal Society of Superior California CA 3026 Theft Laptop 2014-02-21 2013-12-10 +PruittHealth Pharmacy Services GA 841 Theft Laptop 2014-02-25 2013-12-06 +RGH Enterprises, Inc. OH 4230 Theft Network Server 2014-06-24 Computer hackers installed malware that intercepted the electronic protected health information (ePHI) of approximately 4,230 individuals using the covered entity's (CE's) website. The ePHI included names, dates of birth, phone numbers, shipping and billing addresses, email addresses, credit card issuers, expiration dates, the last 4 digits of credit card numbers, account numbers, primary physicians, diagnoses, order histories, and health insurers. Following the breach, the CE removed the malware from the affected computer servers, migrated the website to non-compromised 2013-03-09 2013-03-11 +Network Pharmacy Knoxville TN 9602 Theft Laptop 2014-02-11 2013-11-18 +Saint Francis Hospital and Medical Center CT 858 Theft Paper 2014-03-24 2013-12-27 +Health Dimensions MI 5370 Theft Network Server 2014-02-11 2013-11-02 +COMPLETE MEDICAL HOMECARE KS 1700 Unauthorized Access/Disclosure Other Portable Electronic Device 2014-02-11 2013-12-12 +Hospital for Special Surgery NY 937 Theft Desktop Computer, Paper 2014-02-26 2013-03-19 +The Brooklyn Hospital Center NY 2172 Loss Other Portable Electronic Device 2014-02-24 2013-12-02 +Kmart Corporation IL 16446 Theft Other, Electronic Medical Record 2014-03-24 2014-01-04 +WA State Department of Social & Health Services WA 3104 Unauthorized Access/Disclosure, Other Paper 2014-04-21 2013-08-19 +Lewis J. Sims, DPM, PC dba Sims and Associates Podiatry NY 6475 Theft, Other Laptop 2014-04-21 2014-01-10 +University of Miami FL 13074 Loss Paper 2014-04-21 2013-06-27 +Supportive Concepts for Families, Inc. PA 593 Unauthorized Access/Disclosure Network Server 2014-02-24 2013-02-06 +Health Care Solutions at Home Inc. OH 1139 Other Other 2014-03-12 2013-12-17 +University of California Davis Medical Center CA 2269 Hacking/IT Incident E-mail 2014-04-21 2013-12-13 +St. Vincent Hospital and Healthcare, Inc IN 1142 Theft Laptop 2014-03-12 2013-12-23 +Missouri Consolidated Health Care Plan MO StayWell Health Management, LLC 10024 Unauthorized Access/Disclosure Network Server 2014-03-12 2012-03-23 +The Clorox Company Group Insurance Plan CA StayWell Health Management, LLC 520 Unauthorized Access/Disclosure Network Server 2014-03-12 2012-04-16 +Regents of the University of Minnesota MN StayWell Health Management, LLC 4786 Unauthorized Access/Disclosure Network Server 2014-03-24 2012-03-29 +Inspira Health Network Inc. NJ 1411 Theft Desktop Computer 2014-03-12 2013-12-23 +Nissan North America, Inc. TN StayWell Health Management, LLC 1511 Unauthorized Access/Disclosure Network Server 2014-03-12 2012-05-08 +Care Advantage, Inc. VA 3458 Theft Laptop 2014-03-24 2013-01-01 +HealthSource of Ohio Inc. OH Pair Networks Inc. 8845 Unauthorized Access/Disclosure, Other Other 2014-03-12 2013-11-18 +The Kroger Co., for itself and its affiliates and subsidiaries OH 504 Other Electronic Medical Record 2014-04-21 2013-10-30 +Cornerstone Health Care, PA NC 548 Theft, Loss Laptop 2014-03-12 2013-12-31 +Joseph Michael Benson M.D TX 7500 Theft Desktop Computer 2014-03-24 2014-01-05 +All for Kids Pediatric Clinic AR Data Media 600 Other Other 2014-03-24 2013-12-27 +Eureka Internal Medicine CA 3534 Improper Disposal Paper 2014-03-24 2013-09-25 +Brazos Valley Pathology TX St. Joseph Health System 3300 Hacking/IT Incident Network Server 2014-06-24 2013-12-16 +Banner Health AZ 55207 Other Other 2014-03-24 2014-02-21 +Monarch Women's Health AL PracMan, Inc. 1145 Hacking/IT Incident Network Server 2014-06-02 2013-08-22 +Punuru J.M. Reddy, MD, Inc. AL PracMan, Inc. 1179 Hacking/IT Incident Network Server 2014-03-25 2013-08-22 +Iowa Dept. of Human Services IA 2042 Other Laptop, E-mail, Other Portable Electronic Device 2014-04-21 2008-12-01 +City of Hope CA Sutherland Healthcare Solutions, Inc. 5400 Theft Desktop Computer, E-mail 2014-03-25 2014-02-05 +Mission City Community Network CA 7800 Theft E-mail 2014-04-21 2013-05-31 +Partners In Nephrology & Endocrinology, P.C. PA 5000 Other Other 2014-03-24 2013-11-13 +University of California, San Francisco CA 9861 Theft Desktop Computer 2014-03-31 2014-01-11 +Detroit Medical Center - Harper University Hospital MI 1087 Theft, Unauthorized Access/Disclosure Paper 2014-05-06 2012-09-07 +Todd M. Burton, M.D. TX 5000 Theft Other 2014-03-24 2014-01-13 +Valley View Hospital Association CO 5415 Other Laptop, Desktop Computer 2014-04-21 2013-09-11 +Hospitalists of Arizona AZ 1706 Theft Laptop 2014-03-24 2013-12-31 +McBroom Clinic, PA TX TMA Practice Management Group 2260 Loss, Improper Disposal Other Portable Electronic Device 2014-04-21 2014-01-09 +QBE Holdings, Inc. NY StayWell Health Management, LLC 1746 Unauthorized Access/Disclosure Network Server 2014-04-21 2012-05-09 +Berea College KY 1000 Other Electronic Medical Record 2014-04-21 2012-01-24 +HealthPartners, Inc. MN 27839 Loss, Unauthorized Access/Disclosure Laptop, Desktop Computer, Other Portable Electronic Device 2014-06-20 2008-01-07 +Group Health Plan, Inc. Medical Benefit Plan MN HealthPartners Administrators, Inc. 796 Loss, Unauthorized Access/Disclosure Laptop, Desktop Computer, Other Portable Electronic Device 2014-04-21 2008-01-07 +State Employee Group Insurance Plan MN HealthPartners Administrators, Inc. 1699 Loss, Unauthorized Access/Disclosure Laptop, Desktop Computer, Other Portable Electronic Device 2014-04-21 2008-01-07 +University of Minnesota Employee Benefits MN HealthPartners Administrators, Inc. 715 Loss, Unauthorized Access/Disclosure Laptop, Desktop Computer, Other Portable Electronic Device 2014-04-21 2008-01-07 +San Francisco General Hospital & Trauma Center CA Sutherland Healthcare Solutions 55900 Theft Desktop Computer 2014-05-30 2014-02-05 +University of Kentucky UK HealthCare KY Talyst 1079 Theft Laptop 2014-04-21 2014-02-04 +Yellowstone Boys and Girls Ranch MT 543 Theft Paper 2014-06-24 2013-07-11 +Orlando Health, Inc. FL 586 Loss Other Portable Electronic Device 2014-04-21 2014-01-28 +NOVA Chiropractic & Rehab Center VA 5534 Loss, Other Other Portable Electronic Device 2014-04-21 2014-01-30 +Susquehanna Health PA 657 Unauthorized Access/Disclosure E-mail 2014-04-21 2013-12-05 +Jewish Hospital KY 2992 Other E-mail 2014-04-21 2014-01-15 +Franciscan Medical Group WA 8300 Other E-mail 2014-04-21 2014-01-15 +Palomar Health CA 5499 Theft Other Portable Electronic Device 2014-04-21 2014-02-21 +Myriad Genetic Laboratories, Inc. UT 643 Unauthorized Access/Disclosure E-mail 2014-06-03 2013-03-06 +Medical Center of Plano TX RelayHealth, a division of McKesson 1000 Unauthorized Access/Disclosure Other 2014-06-03 2013-12-10 +Florida Healthy Kids Corporation FL Policy Studies, Inc. / Postal Center International, Inc. 580 Unauthorized Access/Disclosure Paper 2014-04-21 2013-11-13 +Midwest Orthopaedics at Rush, LLC IL 1256 Hacking/IT Incident E-mail 2014-04-21 2014-02-10 +Texas Health and Human Services Commission TX EveryChild, Inc. 2934 Theft Laptop, Desktop Computer, Other Portable Electronic Device 2014-04-21 2014-02-02 +Kaiser Permanente Northern CA Department of Research CA 5178 Hacking/IT Incident Network Server 2014-06-02 2011-10-18 +Triple-S Salud PR 5795 Theft Other 2014-06-24 2013-01-01 +American Health Inc. PR 17776 Theft Other 2014-06-27 2013-01-01 +State Long Term Care Ombudsman's Office, Michigan Department of Community Health MI 2595 Theft Other Portable Electronic Device 2014-04-21 2014-01-30 +County of Los Angeles CA Sutherland Healthcare Solutions, Inc. 338700 Theft Desktop Computer, E-mail 2014-04-21 2014-02-05 +Presence St. Joseph's Medical Center IL 836 Other Paper 2014-06-03 2013-10-22 +Clinical Reference Laboratory, Inc. KS 979 Loss Paper 2014-04-21 2014-02-06 +Various Health Plans CT Cigna 527 Loss Paper 2014-06-27 2014-03-05 +Amerigroup Texas, Inc. VA Amerigroup Texas, Inc. 75026 Theft Paper 2014-05-13 2012-04-01 +BLUE CROSS AND BLUE SHIELD OF KANSAS CITY MO 2546 Unauthorized Access/Disclosure Other 2014-04-21 2013-08-16 +University Urology, P.C. TN 1144 Unauthorized Access/Disclosure Paper 2014-05-13 2013-03-07 +Healthy Connections, Inc CA 793 Loss Other Portable Electronic Device 2014-06-03 2014-03-25 +Administracion de Seguros de Salud PR American Health Medicare 46473 Theft Other Portable Electronic Device 2014-06-03 2013-05-08 +Greenwood Leflore Hospital MS 3750 Theft Other 2014-05-09 2014-02-23 +Maryland Developmental Disabilities Administration MD Service Coordination, Inc. 10766 Unauthorized Access/Disclosure, Hacking/IT Incident Network Server 2014-06-11 2013-11-27 +Los Robles Hospital and Medical Center CA Courier Express/Atlanta, Courier Express/Charlotte & Courier Express US, Inc. 2523 Theft, Unauthorized Access/Disclosure Paper 2014-05-09 2014-02-14 +Shaker Clinic OH 617 Loss Paper 2014-05-27 2014-02-18 +VGM Homelink IA Tri State Adjustments 1400 Other Other 2014-05-27 2014-02-28 +Larsen Dental Care LLC ID 6900 Theft Other Portable Electronic Device 2014-05-27 2014-03-04 +The Union Labor Life Insurance Company MD 46771 Theft Laptop 2014-05-27 2014-02-17 +Coordinated Health PA 733 Theft Laptop 2014-05-29 2014-02-21 +CENTURA HEALTH CO 12286 Hacking/IT Incident E-mail 2014-05-29 2014-02-11 +Ladies First Choice, Inc. FL 2365 Theft, Unauthorized Access/Disclosure Laptop 2014-05-29 2013-01-01 +Tufts Associated Health Maintenance Organization, Inc. and Tufts Insurance Company MA 8830 Theft Other 2014-05-09 2014-04-10 +Developmental Disabilities Administration MD Inclusion Research Institute 2200 Unauthorized Access/Disclosure Paper 2014-05-29 2014-03-03 +Willis North America Inc. Medical Expense Benefit Plan NY 4830 Unauthorized Access/Disclosure E-mail 2014-05-29 2014-03-19 +Sorenson Communications/CaptionCall Group Health Plan UT Sorenson Communications 9800 Hacking/IT Incident Network Server 2014-05-27 2014-02-20 +Baylor Medical Center at McKinney TX 1253 Hacking/IT Incident E-mail 2014-05-09 2014-01-23 +Baylor Medical Center at Irving TX 2308 Hacking/IT Incident E-mail 2014-05-09 2014-01-23 +Baylor Regional Medical Center at Plano TX 1981 Hacking/IT Incident E-mail 2014-05-07 2014-01-23 +HealthTexas Provider Network TX 2742 Hacking/IT Incident E-mail 2014-05-07 2014-01-23 +DeKalb Health IN Ferguson Advertising, Inc. 1361 Hacking/IT Incident Network Server 2014-05-27 2014-02-09 +Iowa Medicaid Enterprise IA 862 Unauthorized Access/Disclosure Paper 2014-05-29 2014-02-26 +Flowers Hospital AL 629 Theft Paper 2014-06-20 2013-06-03 +Reading Health System PA 1845 Loss Paper 2014-05-27 2012-03-02 +City of Cincinnati OH OptumRx 5696 Other Paper 2014-05-07 2014-04-04 +UMass Memorial Medical Center MA 2387 Unauthorized Access/Disclosure Electronic Medical Record, Paper 2014-05-27 2002-05-06 +The City of Henderson KY KEYSTONE INSURERS GROUP 1008 Other E-mail 2014-05-27 2012-06-27 +Options Counseling Center NJ 2828 Theft, Unauthorized Access/Disclosure Paper 2014-06-18 2011-05-01 +Molina Healthcare of California Partner Plan, Inc. CA Creel Printing 4744 Other Paper 2014-05-27 2014-03-18 +Howard L. Weinstein D.P.M. TX 1000 Theft Laptop 2014-05-27 2014-03-13 +Bio-Reference Laboratories, Inc. NJ Xand Corporation 1749 Other Network Server 2014-06-18 2014-02-02 +American Health Inc. PR 11531 Unauthorized Access/Disclosure Paper 2014-06-18 2013-09-20 +Central City Concern OR 17914 Unauthorized Access/Disclosure Other 2014-06-18 2010-03-23 +Blue Cross Blue Shield of Michigan/Blue Care Network MI Bloom Health 502 Unauthorized Access/Disclosure, Hacking/IT Incident E-mail 2014-06-18 2014-02-15 +Elliot Health System NH 1208 Theft Desktop Computer 2014-06-18 2014-03-26 +Humana Inc [case #15381] KY 2962 Theft Other Portable Electronic Device 2014-06-18 2014-04-02 +Jamaica Hospital Medical Center NY 26162 Unauthorized Access/Disclosure Desktop Computer 2014-06-18 2011-08-01 +Bay Park Hospital OH 594 Unauthorized Access/Disclosure Network Server, Electronic Medical Record 2014-06-18 2013-04-01 +Triple-S Salud PR 56853 Unauthorized Access/Disclosure Paper 2014-06-18 2013-09-20 +Aetna Life Insurance Company CT NFP Maschino, Hudelson & Associates 3814 Theft Laptop 2014-06-18 2014-04-02 +Salina Health Education Foundation dba Salina Family Healthcare Center KS 9640 Unauthorized Access/Disclosure E-mail 2014-06-20 2014-04-08 +Highmark Inc. PA 2589 Loss, Unauthorized Access/Disclosure Paper 2014-06-27 2014-04-19 +Mark A. Gillispie CA 5845 Theft Desktop Computer 2014-06-27 2013-11-20 +Penn State Milton S Hershey Medical Center PA 1801 Other E-mail, Other Portable Electronic Device 2014-06-27 2013-09-13 +Walgreen Co. IL 540 Theft Desktop Computer, Paper 2014-06-20 2014-03-03 +St. Francis Hospital GA 1175 Other E-mail 2014-06-18 2014-05-30 +Puerto Rico Health Insurance PR American Health Inc 28413 Theft Other 2014-06-27 2013-09-20 +Hospitalists of Brandon, LLC FL Doctors First Choice Billings, Inc. 1831 Hacking/IT Incident Other 2014-06-27 2014-02-11 +Santa Rosa Memorial Hospital CA 33702 Theft, Loss Other Portable Electronic Device 2014-06-27 2014-06-02 +Group Health Plan of Hurley Medical Center MI 2289 Unauthorized Access/Disclosure E-mail 2014-06-27 2014-05-13 +Abrham Tekola, M.D.,INC CA 5471 Theft Desktop Computer 2014-06-27 2014-05-27 diff --git a/pyminer2/tests/datasets/imports-85.tab b/pyminer2/tests/datasets/imports-85.tab new file mode 100644 index 0000000000000000000000000000000000000000..f19b4f6470ee986e0f8837fdcb6f6e18a23e00cd --- /dev/null +++ b/pyminer2/tests/datasets/imports-85.tab @@ -0,0 +1,208 @@ +symboling normalized-losses make fuel-type aspiration num-of-doors body-style drive-wheels engine-location wheel-base length width height curb-weight engine-type num-of-cylinders engine-size fuel-system bore stroke compression-ratio horsepower peak-rpm city-mpg highway-mpg price +d c d d d d d d d c c c c c d d c d c c c c c c c c + class +3 ? alfa-romero gas std two convertible rwd front 88.60 168.80 64.10 48.80 2548 dohc four 130 mpfi 3.47 2.68 9.00 111 5000 21 27 13495 +3 ? alfa-romero gas std two convertible rwd front 88.60 168.80 64.10 48.80 2548 dohc four 130 mpfi 3.47 2.68 9.00 111 5000 21 27 16500 +1 ? alfa-romero gas std two hatchback rwd front 94.50 171.20 65.50 52.40 2823 ohcv six 152 mpfi 2.68 3.47 9.00 154 5000 19 26 16500 +2 164 audi gas std four sedan fwd front 99.80 176.60 66.20 54.30 2337 ohc four 109 mpfi 3.19 3.40 10.00 102 5500 24 30 13950 +2 164 audi gas std four sedan 4wd front 99.40 176.60 66.40 54.30 2824 ohc five 136 mpfi 3.19 3.40 8.00 115 5500 18 22 17450 +2 ? audi gas std two sedan fwd front 99.80 177.30 66.30 53.10 2507 ohc five 136 mpfi 3.19 3.40 8.50 110 5500 19 25 15250 +1 158 audi gas std four sedan fwd front 105.80 192.70 71.40 55.70 2844 ohc five 136 mpfi 3.19 3.40 8.50 110 5500 19 25 17710 +1 ? audi gas std four wagon fwd front 105.80 192.70 71.40 55.70 2954 ohc five 136 mpfi 3.19 3.40 8.50 110 5500 19 25 18920 +1 158 audi gas turbo four sedan fwd front 105.80 192.70 71.40 55.90 3086 ohc five 131 mpfi 3.13 3.40 8.30 140 5500 17 20 23875 +0 ? audi gas turbo two hatchback 4wd front 99.50 178.20 67.90 52.00 3053 ohc five 131 mpfi 3.13 3.40 7.00 160 5500 16 22 ? +2 192 bmw gas std two sedan rwd front 101.20 176.80 64.80 54.30 2395 ohc four 108 mpfi 3.50 2.80 8.80 101 5800 23 29 16430 +0 192 bmw gas std four sedan rwd front 101.20 176.80 64.80 54.30 2395 ohc four 108 mpfi 3.50 2.80 8.80 101 5800 23 29 16925 +0 188 bmw gas std two sedan rwd front 101.20 176.80 64.80 54.30 2710 ohc six 164 mpfi 3.31 3.19 9.00 121 4250 21 28 20970 +0 188 bmw gas std four sedan rwd front 101.20 176.80 64.80 54.30 2765 ohc six 164 mpfi 3.31 3.19 9.00 121 4250 21 28 21105 +1 ? bmw gas std four sedan rwd front 103.50 189.00 66.90 55.70 3055 ohc six 164 mpfi 3.31 3.19 9.00 121 4250 20 25 24565 +0 ? bmw gas std four sedan rwd front 103.50 189.00 66.90 55.70 3230 ohc six 209 mpfi 3.62 3.39 8.00 182 5400 16 22 30760 +0 ? bmw gas std two sedan rwd front 103.50 193.80 67.90 53.70 3380 ohc six 209 mpfi 3.62 3.39 8.00 182 5400 16 22 41315 +0 ? bmw gas std four sedan rwd front 110.00 197.00 70.90 56.30 3505 ohc six 209 mpfi 3.62 3.39 8.00 182 5400 15 20 36880 +2 121 chevrolet gas std two hatchback fwd front 88.40 141.10 60.30 53.20 1488 l three 61 2bbl 2.91 3.03 9.50 48 5100 47 53 5151 +1 98 chevrolet gas std two hatchback fwd front 94.50 155.90 63.60 52.00 1874 ohc four 90 2bbl 3.03 3.11 9.60 70 5400 38 43 6295 +0 81 chevrolet gas std four sedan fwd front 94.50 158.80 63.60 52.00 1909 ohc four 90 2bbl 3.03 3.11 9.60 70 5400 38 43 6575 +1 118 dodge gas std two hatchback fwd front 93.70 157.30 63.80 50.80 1876 ohc four 90 2bbl 2.97 3.23 9.41 68 5500 37 41 5572 +1 118 dodge gas std two hatchback fwd front 93.70 157.30 63.80 50.80 1876 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 6377 +1 118 dodge gas turbo two hatchback fwd front 93.70 157.30 63.80 50.80 2128 ohc four 98 mpfi 3.03 3.39 7.60 102 5500 24 30 7957 +1 148 dodge gas std four hatchback fwd front 93.70 157.30 63.80 50.60 1967 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 6229 +1 148 dodge gas std four sedan fwd front 93.70 157.30 63.80 50.60 1989 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 6692 +1 148 dodge gas std four sedan fwd front 93.70 157.30 63.80 50.60 1989 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 7609 +1 148 dodge gas turbo ? sedan fwd front 93.70 157.30 63.80 50.60 2191 ohc four 98 mpfi 3.03 3.39 7.60 102 5500 24 30 8558 +-1 110 dodge gas std four wagon fwd front 103.30 174.60 64.60 59.80 2535 ohc four 122 2bbl 3.34 3.46 8.50 88 5000 24 30 8921 +3 145 dodge gas turbo two hatchback fwd front 95.90 173.20 66.30 50.20 2811 ohc four 156 mfi 3.60 3.90 7.00 145 5000 19 24 12964 +2 137 honda gas std two hatchback fwd front 86.60 144.60 63.90 50.80 1713 ohc four 92 1bbl 2.91 3.41 9.60 58 4800 49 54 6479 +2 137 honda gas std two hatchback fwd front 86.60 144.60 63.90 50.80 1819 ohc four 92 1bbl 2.91 3.41 9.20 76 6000 31 38 6855 +1 101 honda gas std two hatchback fwd front 93.70 150.00 64.00 52.60 1837 ohc four 79 1bbl 2.91 3.07 10.10 60 5500 38 42 5399 +1 101 honda gas std two hatchback fwd front 93.70 150.00 64.00 52.60 1940 ohc four 92 1bbl 2.91 3.41 9.20 76 6000 30 34 6529 +1 101 honda gas std two hatchback fwd front 93.70 150.00 64.00 52.60 1956 ohc four 92 1bbl 2.91 3.41 9.20 76 6000 30 34 7129 +0 110 honda gas std four sedan fwd front 96.50 163.40 64.00 54.50 2010 ohc four 92 1bbl 2.91 3.41 9.20 76 6000 30 34 7295 +0 78 honda gas std four wagon fwd front 96.50 157.10 63.90 58.30 2024 ohc four 92 1bbl 2.92 3.41 9.20 76 6000 30 34 7295 +0 106 honda gas std two hatchback fwd front 96.50 167.50 65.20 53.30 2236 ohc four 110 1bbl 3.15 3.58 9.00 86 5800 27 33 7895 +0 106 honda gas std two hatchback fwd front 96.50 167.50 65.20 53.30 2289 ohc four 110 1bbl 3.15 3.58 9.00 86 5800 27 33 9095 +0 85 honda gas std four sedan fwd front 96.50 175.40 65.20 54.10 2304 ohc four 110 1bbl 3.15 3.58 9.00 86 5800 27 33 8845 +0 85 honda gas std four sedan fwd front 96.50 175.40 62.50 54.10 2372 ohc four 110 1bbl 3.15 3.58 9.00 86 5800 27 33 10295 +0 85 honda gas std four sedan fwd front 96.50 175.40 65.20 54.10 2465 ohc four 110 mpfi 3.15 3.58 9.00 101 5800 24 28 12945 +1 107 honda gas std two sedan fwd front 96.50 169.10 66.00 51.00 2293 ohc four 110 2bbl 3.15 3.58 9.10 100 5500 25 31 10345 +0 ? isuzu gas std four sedan rwd front 94.30 170.70 61.80 53.50 2337 ohc four 111 2bbl 3.31 3.23 8.50 78 4800 24 29 6785 +1 ? isuzu gas std two sedan fwd front 94.50 155.90 63.60 52.00 1874 ohc four 90 2bbl 3.03 3.11 9.60 70 5400 38 43 ? +0 ? isuzu gas std four sedan fwd front 94.50 155.90 63.60 52.00 1909 ohc four 90 2bbl 3.03 3.11 9.60 70 5400 38 43 ? +2 ? isuzu gas std two hatchback rwd front 96.00 172.60 65.20 51.40 2734 ohc four 119 spfi 3.43 3.23 9.20 90 5000 24 29 11048 +0 145 jaguar gas std four sedan rwd front 113.00 199.60 69.60 52.80 4066 dohc six 258 mpfi 3.63 4.17 8.10 176 4750 15 19 32250 +0 ? jaguar gas std four sedan rwd front 113.00 199.60 69.60 52.80 4066 dohc six 258 mpfi 3.63 4.17 8.10 176 4750 15 19 35550 +0 ? jaguar gas std two sedan rwd front 102.00 191.70 70.60 47.80 3950 ohcv twelve 326 mpfi 3.54 2.76 11.50 262 5000 13 17 36000 +1 104 mazda gas std two hatchback fwd front 93.10 159.10 64.20 54.10 1890 ohc four 91 2bbl 3.03 3.15 9.00 68 5000 30 31 5195 +1 104 mazda gas std two hatchback fwd front 93.10 159.10 64.20 54.10 1900 ohc four 91 2bbl 3.03 3.15 9.00 68 5000 31 38 6095 +1 104 mazda gas std two hatchback fwd front 93.10 159.10 64.20 54.10 1905 ohc four 91 2bbl 3.03 3.15 9.00 68 5000 31 38 6795 +1 113 mazda gas std four sedan fwd front 93.10 166.80 64.20 54.10 1945 ohc four 91 2bbl 3.03 3.15 9.00 68 5000 31 38 6695 +1 113 mazda gas std four sedan fwd front 93.10 166.80 64.20 54.10 1950 ohc four 91 2bbl 3.08 3.15 9.00 68 5000 31 38 7395 +3 150 mazda gas std two hatchback rwd front 95.30 169.00 65.70 49.60 2380 rotor two 70 4bbl ? ? 9.40 101 6000 17 23 10945 +3 150 mazda gas std two hatchback rwd front 95.30 169.00 65.70 49.60 2380 rotor two 70 4bbl ? ? 9.40 101 6000 17 23 11845 +3 150 mazda gas std two hatchback rwd front 95.30 169.00 65.70 49.60 2385 rotor two 70 4bbl ? ? 9.40 101 6000 17 23 13645 +3 150 mazda gas std two hatchback rwd front 95.30 169.00 65.70 49.60 2500 rotor two 80 mpfi ? ? 9.40 135 6000 16 23 15645 +1 129 mazda gas std two hatchback fwd front 98.80 177.80 66.50 53.70 2385 ohc four 122 2bbl 3.39 3.39 8.60 84 4800 26 32 8845 +0 115 mazda gas std four sedan fwd front 98.80 177.80 66.50 55.50 2410 ohc four 122 2bbl 3.39 3.39 8.60 84 4800 26 32 8495 +1 129 mazda gas std two hatchback fwd front 98.80 177.80 66.50 53.70 2385 ohc four 122 2bbl 3.39 3.39 8.60 84 4800 26 32 10595 +0 115 mazda gas std four sedan fwd front 98.80 177.80 66.50 55.50 2410 ohc four 122 2bbl 3.39 3.39 8.60 84 4800 26 32 10245 +0 ? mazda diesel std ? sedan fwd front 98.80 177.80 66.50 55.50 2443 ohc four 122 idi 3.39 3.39 22.70 64 4650 36 42 10795 +0 115 mazda gas std four hatchback fwd front 98.80 177.80 66.50 55.50 2425 ohc four 122 2bbl 3.39 3.39 8.60 84 4800 26 32 11245 +0 118 mazda gas std four sedan rwd front 104.90 175.00 66.10 54.40 2670 ohc four 140 mpfi 3.76 3.16 8.00 120 5000 19 27 18280 +0 ? mazda diesel std four sedan rwd front 104.90 175.00 66.10 54.40 2700 ohc four 134 idi 3.43 3.64 22.00 72 4200 31 39 18344 +-1 93 mercedes-benz diesel turbo four sedan rwd front 110.00 190.90 70.30 56.50 3515 ohc five 183 idi 3.58 3.64 21.50 123 4350 22 25 25552 +-1 93 mercedes-benz diesel turbo four wagon rwd front 110.00 190.90 70.30 58.70 3750 ohc five 183 idi 3.58 3.64 21.50 123 4350 22 25 28248 +0 93 mercedes-benz diesel turbo two hardtop rwd front 106.70 187.50 70.30 54.90 3495 ohc five 183 idi 3.58 3.64 21.50 123 4350 22 25 28176 +-1 93 mercedes-benz diesel turbo four sedan rwd front 115.60 202.60 71.70 56.30 3770 ohc five 183 idi 3.58 3.64 21.50 123 4350 22 25 31600 +-1 ? mercedes-benz gas std four sedan rwd front 115.60 202.60 71.70 56.50 3740 ohcv eight 234 mpfi 3.46 3.10 8.30 155 4750 16 18 34184 +3 142 mercedes-benz gas std two convertible rwd front 96.60 180.30 70.50 50.80 3685 ohcv eight 234 mpfi 3.46 3.10 8.30 155 4750 16 18 35056 +0 ? mercedes-benz gas std four sedan rwd front 120.90 208.10 71.70 56.70 3900 ohcv eight 308 mpfi 3.80 3.35 8.00 184 4500 14 16 40960 +1 ? mercedes-benz gas std two hardtop rwd front 112.00 199.20 72.00 55.40 3715 ohcv eight 304 mpfi 3.80 3.35 8.00 184 4500 14 16 45400 +1 ? mercury gas turbo two hatchback rwd front 102.70 178.40 68.00 54.80 2910 ohc four 140 mpfi 3.78 3.12 8.00 175 5000 19 24 16503 +2 161 mitsubishi gas std two hatchback fwd front 93.70 157.30 64.40 50.80 1918 ohc four 92 2bbl 2.97 3.23 9.40 68 5500 37 41 5389 +2 161 mitsubishi gas std two hatchback fwd front 93.70 157.30 64.40 50.80 1944 ohc four 92 2bbl 2.97 3.23 9.40 68 5500 31 38 6189 +2 161 mitsubishi gas std two hatchback fwd front 93.70 157.30 64.40 50.80 2004 ohc four 92 2bbl 2.97 3.23 9.40 68 5500 31 38 6669 +1 161 mitsubishi gas turbo two hatchback fwd front 93 157.30 63.80 50.80 2145 ohc four 98 spdi 3.03 3.39 7.60 102 5500 24 30 7689 +3 153 mitsubishi gas turbo two hatchback fwd front 96.30 173.00 65.40 49.40 2370 ohc four 110 spdi 3.17 3.46 7.50 116 5500 23 30 9959 +3 153 mitsubishi gas std two hatchback fwd front 96.30 173.00 65.40 49.40 2328 ohc four 122 2bbl 3.35 3.46 8.50 88 5000 25 32 8499 +3 ? mitsubishi gas turbo two hatchback fwd front 95.90 173.20 66.30 50.20 2833 ohc four 156 spdi 3.58 3.86 7.00 145 5000 19 24 12629 +3 ? mitsubishi gas turbo two hatchback fwd front 95.90 173.20 66.30 50.20 2921 ohc four 156 spdi 3.59 3.86 7.00 145 5000 19 24 14869 +3 ? mitsubishi gas turbo two hatchback fwd front 95.90 173.20 66.30 50.20 2926 ohc four 156 spdi 3.59 3.86 7.00 145 5000 19 24 14489 +1 125 mitsubishi gas std four sedan fwd front 96.30 172.40 65.40 51.60 2365 ohc four 122 2bbl 3.35 3.46 8.50 88 5000 25 32 6989 +1 125 mitsubishi gas std four sedan fwd front 96.30 172.40 65.40 51.60 2405 ohc four 122 2bbl 3.35 3.46 8.50 88 5000 25 32 8189 +1 125 mitsubishi gas turbo four sedan fwd front 96.30 172.40 65.40 51.60 2403 ohc four 110 spdi 3.17 3.46 7.50 116 5500 23 30 9279 +-1 137 mitsubishi gas std four sedan fwd front 96.30 172.40 65.40 51.60 2403 ohc four 110 spdi 3.17 3.46 7.50 116 5500 23 30 9279 +1 128 nissan gas std two sedan fwd front 94.50 165.30 63.80 54.50 1889 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 5499 +1 128 nissan diesel std two sedan fwd front 94.50 165.30 63.80 54.50 2017 ohc four 103 idi 2.99 3.47 21.90 55 4800 45 50 7099 +1 128 nissan gas std two sedan fwd front 94.50 165.30 63.80 54.50 1918 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 6649 +1 122 nissan gas std four sedan fwd front 94.50 165.30 63.80 54.50 1938 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 6849 +1 103 nissan gas std four wagon fwd front 94.50 170.20 63.80 53.50 2024 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 7349 +1 128 nissan gas std two sedan fwd front 94.50 165.30 63.80 54.50 1951 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 7299 +1 128 nissan gas std two hatchback fwd front 94.50 165.60 63.80 53.30 2028 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 7799 +1 122 nissan gas std four sedan fwd front 94.50 165.30 63.80 54.50 1971 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 7499 +1 103 nissan gas std four wagon fwd front 94.50 170.20 63.80 53.50 2037 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 7999 +2 168 nissan gas std two hardtop fwd front 95.10 162.40 63.80 53.30 2008 ohc four 97 2bbl 3.15 3.29 9.40 69 5200 31 37 8249 +0 106 nissan gas std four hatchback fwd front 97.20 173.40 65.20 54.70 2324 ohc four 120 2bbl 3.33 3.47 8.50 97 5200 27 34 8949 +0 106 nissan gas std four sedan fwd front 97.20 173.40 65.20 54.70 2302 ohc four 120 2bbl 3.33 3.47 8.50 97 5200 27 34 9549 +0 128 nissan gas std four sedan fwd front 100.40 181.70 66.50 55.10 3095 ohcv six 181 mpfi 3.43 3.27 9.00 152 5200 17 22 13499 +0 108 nissan gas std four wagon fwd front 100.40 184.60 66.50 56.10 3296 ohcv six 181 mpfi 3.43 3.27 9.00 152 5200 17 22 14399 +0 108 nissan gas std four sedan fwd front 100.40 184.60 66.50 55.10 3060 ohcv six 181 mpfi 3.43 3.27 9.00 152 5200 19 25 13499 +3 194 nissan gas std two hatchback rwd front 91.30 170.70 67.90 49.70 3071 ohcv six 181 mpfi 3.43 3.27 9.00 160 5200 19 25 17199 +3 194 nissan gas turbo two hatchback rwd front 91.30 170.70 67.90 49.70 3139 ohcv six 181 mpfi 3.43 3.27 7.80 200 5200 17 23 19699 +1 231 nissan gas std two hatchback rwd front 99.20 178.50 67.90 49.70 3139 ohcv six 181 mpfi 3.43 3.27 9.00 160 5200 19 25 18399 +0 161 peugot gas std four sedan rwd front 107.90 186.70 68.40 56.70 3020 l four 120 mpfi 3.46 3.19 8.40 97 5000 19 24 11900 +0 161 peugot diesel turbo four sedan rwd front 107.90 186.70 68.40 56.70 3197 l four 152 idi 3.70 3.52 21.00 95 4150 28 33 13200 +0 ? peugot gas std four wagon rwd front 114.20 198.90 68.40 58.70 3230 l four 120 mpfi 3.46 3.19 8.40 97 5000 19 24 12440 +0 ? peugot diesel turbo four wagon rwd front 114.20 198.90 68.40 58.70 3430 l four 152 idi 3.70 3.52 21.00 95 4150 25 25 13860 +0 161 peugot gas std four sedan rwd front 107.90 186.70 68.40 56.70 3075 l four 120 mpfi 3.46 2.19 8.40 95 5000 19 24 15580 +0 161 peugot diesel turbo four sedan rwd front 107.90 186.70 68.40 56.70 3252 l four 152 idi 3.70 3.52 21.00 95 4150 28 33 16900 +0 ? peugot gas std four wagon rwd front 114.20 198.90 68.40 56.70 3285 l four 120 mpfi 3.46 2.19 8.40 95 5000 19 24 16695 +0 ? peugot diesel turbo four wagon rwd front 114.20 198.90 68.40 58.70 3485 l four 152 idi 3.70 3.52 21.00 95 4150 25 25 17075 +0 161 peugot gas std four sedan rwd front 107.90 186.70 68.40 56.70 3075 l four 120 mpfi 3.46 3.19 8.40 97 5000 19 24 16630 +0 161 peugot diesel turbo four sedan rwd front 107.90 186.70 68.40 56.70 3252 l four 152 idi 3.70 3.52 21.00 95 4150 28 33 17950 +0 161 peugot gas turbo four sedan rwd front 108.00 186.70 68.30 56.00 3130 l four 134 mpfi 3.61 3.21 7.00 142 5600 18 24 18150 +1 119 plymouth gas std two hatchback fwd front 93.70 157.30 63.80 50.80 1918 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 37 41 5572 +1 119 plymouth gas turbo two hatchback fwd front 93.70 157.30 63.80 50.80 2128 ohc four 98 spdi 3.03 3.39 7.60 102 5500 24 30 7957 +1 154 plymouth gas std four hatchback fwd front 93.70 157.30 63.80 50.60 1967 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 6229 +1 154 plymouth gas std four sedan fwd front 93.70 167.30 63.80 50.80 1989 ohc four 90 2bbl 2.97 3.23 9.40 68 5500 31 38 6692 +1 154 plymouth gas std four sedan fwd front 93.70 167.30 63.80 50.80 2191 ohc four 98 2bbl 2.97 3.23 9.40 68 5500 31 38 7609 +-1 74 plymouth gas std four wagon fwd front 103.30 174.60 64.60 59.80 2535 ohc four 122 2bbl 3.35 3.46 8.50 88 5000 24 30 8921 +3 ? plymouth gas turbo two hatchback rwd front 95.90 173.20 66.30 50.20 2818 ohc four 156 spdi 3.59 3.86 7.00 145 5000 19 24 12764 +3 186 porsche gas std two hatchback rwd front 94.50 168.90 68.30 50.20 2778 ohc four 151 mpfi 3.94 3.11 9.50 143 5500 19 27 22018 +3 ? porsche gas std two hardtop rwd rear 89.50 168.90 65.00 51.60 2756 ohcf six 194 mpfi 3.74 2.90 9.50 207 5900 17 25 32528 +3 ? porsche gas std two hardtop rwd rear 89.50 168.90 65.00 51.60 2756 ohcf six 194 mpfi 3.74 2.90 9.50 207 5900 17 25 34028 +3 ? porsche gas std two convertible rwd rear 89.50 168.90 65.00 51.60 2800 ohcf six 194 mpfi 3.74 2.90 9.50 207 5900 17 25 37028 +1 ? porsche gas std two hatchback rwd front 98.40 175.70 72.30 50.50 3366 dohcv eight 203 mpfi 3.94 3.11 10.00 288 5750 17 28 ? +0 ? renault gas std four wagon fwd front 96.10 181.50 66.50 55.20 2579 ohc four 132 mpfi 3.46 3.90 8.70 ? ? 23 31 9295 +2 ? renault gas std two hatchback fwd front 96.10 176.80 66.60 50.50 2460 ohc four 132 mpfi 3.46 3.90 8.70 ? ? 23 31 9895 +3 150 saab gas std two hatchback fwd front 99.10 186.60 66.50 56.10 2658 ohc four 121 mpfi 3.54 3.07 9.31 110 5250 21 28 11850 +2 104 saab gas std four sedan fwd front 99.10 186.60 66.50 56.10 2695 ohc four 121 mpfi 3.54 3.07 9.30 110 5250 21 28 12170 +3 150 saab gas std two hatchback fwd front 99.10 186.60 66.50 56.10 2707 ohc four 121 mpfi 2.54 2.07 9.30 110 5250 21 28 15040 +2 104 saab gas std four sedan fwd front 99.10 186.60 66.50 56.10 2758 ohc four 121 mpfi 3.54 3.07 9.30 110 5250 21 28 15510 +3 150 saab gas turbo two hatchback fwd front 99.10 186.60 66.50 56.10 2808 dohc four 121 mpfi 3.54 3.07 9.00 160 5500 19 26 18150 +2 104 saab gas turbo four sedan fwd front 99.10 186.60 66.50 56.10 2847 dohc four 121 mpfi 3.54 3.07 9.00 160 5500 19 26 18620 +2 83 subaru gas std two hatchback fwd front 93.70 156.90 63.40 53.70 2050 ohcf four 97 2bbl 3.62 2.36 9.00 69 4900 31 36 5118 +2 83 subaru gas std two hatchback fwd front 93.70 157.90 63.60 53.70 2120 ohcf four 108 2bbl 3.62 2.64 8.70 73 4400 26 31 7053 +2 83 subaru gas std two hatchback 4wd front 93.30 157.30 63.80 55.70 2240 ohcf four 108 2bbl 3.62 2.64 8.70 73 4400 26 31 7603 +0 102 subaru gas std four sedan fwd front 97.20 172.00 65.40 52.50 2145 ohcf four 108 2bbl 3.62 2.64 9.50 82 4800 32 37 7126 +0 102 subaru gas std four sedan fwd front 97.20 172.00 65.40 52.50 2190 ohcf four 108 2bbl 3.62 2.64 9.50 82 4400 28 33 7775 +0 102 subaru gas std four sedan fwd front 97.20 172.00 65.40 52.50 2340 ohcf four 108 mpfi 3.62 2.64 9.00 94 5200 26 32 9960 +0 102 subaru gas std four sedan 4wd front 97.00 172.00 65.40 54.30 2385 ohcf four 108 2bbl 3.62 2.64 9.00 82 4800 24 25 9233 +0 102 subaru gas turbo four sedan 4wd front 97.00 172.00 65.40 54.30 2510 ohcf four 108 mpfi 3.62 2.64 7.70 111 4800 24 29 11259 +0 89 subaru gas std four wagon fwd front 97.00 173.50 65.40 53.00 2290 ohcf four 108 2bbl 3.62 2.64 9.00 82 4800 28 32 7463 +0 89 subaru gas std four wagon fwd front 97.00 173.50 65.40 53.00 2455 ohcf four 108 mpfi 3.62 2.64 9.00 94 5200 25 31 10198 +0 85 subaru gas std four wagon 4wd front 96.90 173.60 65.40 54.90 2420 ohcf four 108 2bbl 3.62 2.64 9.00 82 4800 23 29 8013 +0 85 subaru gas turbo four wagon 4wd front 96.90 173.60 65.40 54.90 2650 ohcf four 108 mpfi 3.62 2.64 7.70 111 4800 23 23 11694 +1 87 toyota gas std two hatchback fwd front 95.70 158.70 63.60 54.50 1985 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 35 39 5348 +1 87 toyota gas std two hatchback fwd front 95.70 158.70 63.60 54.50 2040 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 31 38 6338 +1 74 toyota gas std four hatchback fwd front 95.70 158.70 63.60 54.50 2015 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 31 38 6488 +0 77 toyota gas std four wagon fwd front 95.70 169.70 63.60 59.10 2280 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 31 37 6918 +0 81 toyota gas std four wagon 4wd front 95.70 169.70 63.60 59.10 2290 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 27 32 7898 +0 91 toyota gas std four wagon 4wd front 95.70 169.70 63.60 59.10 3110 ohc four 92 2bbl 3.05 3.03 9.00 62 4800 27 32 8778 +0 91 toyota gas std four sedan fwd front 95.70 166.30 64.40 53.00 2081 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 30 37 6938 +0 91 toyota gas std four hatchback fwd front 95.70 166.30 64.40 52.80 2109 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 30 37 7198 +0 91 toyota diesel std four sedan fwd front 95.70 166.30 64.40 53.00 2275 ohc four 110 idi 3.27 3.35 22.50 56 4500 34 36 7898 +0 91 toyota diesel std four hatchback fwd front 95.70 166.30 64.40 52.80 2275 ohc four 110 idi 3.27 3.35 22.50 56 4500 38 47 7788 +0 91 toyota gas std four sedan fwd front 95.70 166.30 64.40 53.00 2094 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 38 47 7738 +0 91 toyota gas std four hatchback fwd front 95.70 166.30 64.40 52.80 2122 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 28 34 8358 +0 91 toyota gas std four sedan fwd front 95.70 166.30 64.40 52.80 2140 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 28 34 9258 +1 168 toyota gas std two sedan rwd front 94.50 168.70 64.00 52.60 2169 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 29 34 8058 +1 168 toyota gas std two hatchback rwd front 94.50 168.70 64.00 52.60 2204 ohc four 98 2bbl 3.19 3.03 9.00 70 4800 29 34 8238 +1 168 toyota gas std two sedan rwd front 94.50 168.70 64.00 52.60 2265 dohc four 98 mpfi 3.24 3.08 9.40 112 6600 26 29 9298 +1 168 toyota gas std two hatchback rwd front 94.50 168.70 64.00 52.60 2300 dohc four 98 mpfi 3.24 3.08 9.40 112 6600 26 29 9538 +2 134 toyota gas std two hardtop rwd front 98.40 176.20 65.60 52.00 2540 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 8449 +2 134 toyota gas std two hardtop rwd front 98.40 176.20 65.60 52.00 2536 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 9639 +2 134 toyota gas std two hatchback rwd front 98.40 176.20 65.60 52.00 2551 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 9989 +2 134 toyota gas std two hardtop rwd front 98.40 176.20 65.60 52.00 2679 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 11199 +2 134 toyota gas std two hatchback rwd front 98.40 176.20 65.60 52.00 2714 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 11549 +2 134 toyota gas std two convertible rwd front 98.40 176.20 65.60 53.00 2975 ohc four 146 mpfi 3.62 3.50 9.30 116 4800 24 30 17669 +-1 65 toyota gas std four sedan fwd front 102.40 175.60 66.50 54.90 2326 ohc four 122 mpfi 3.31 3.54 8.70 92 4200 29 34 8948 +-1 65 toyota diesel turbo four sedan fwd front 102.40 175.60 66.50 54.90 2480 ohc four 110 idi 3.27 3.35 22.50 73 4500 30 33 10698 +-1 65 toyota gas std four hatchback fwd front 102.40 175.60 66.50 53.90 2414 ohc four 122 mpfi 3.31 3.54 8.70 92 4200 27 32 9988 +-1 65 toyota gas std four sedan fwd front 102.40 175.60 66.50 54.90 2414 ohc four 122 mpfi 3.31 3.54 8.70 92 4200 27 32 10898 +-1 65 toyota gas std four hatchback fwd front 102.40 175.60 66.50 53.90 2458 ohc four 122 mpfi 3.31 3.54 8.70 92 4200 27 32 11248 +3 197 toyota gas std two hatchback rwd front 102.90 183.50 67.70 52.00 2976 dohc six 171 mpfi 3.27 3.35 9.30 161 5200 20 24 16558 +3 197 toyota gas std two hatchback rwd front 102.90 183.50 67.70 52.00 3016 dohc six 171 mpfi 3.27 3.35 9.30 161 5200 19 24 15998 +-1 90 toyota gas std four sedan rwd front 104.50 187.80 66.50 54.10 3131 dohc six 171 mpfi 3.27 3.35 9.20 156 5200 20 24 15690 +-1 ? toyota gas std four wagon rwd front 104.50 187.80 66.50 54.10 3151 dohc six 161 mpfi 3.27 3.35 9.20 156 5200 19 24 15750 +2 122 volkswagen diesel std two sedan fwd front 97.30 171.70 65.50 55.70 2261 ohc four 97 idi 3.01 3.40 23.00 52 4800 37 46 7775 +2 122 volkswagen gas std two sedan fwd front 97.30 171.70 65.50 55.70 2209 ohc four 109 mpfi 3.19 3.40 9.00 85 5250 27 34 7975 +2 94 volkswagen diesel std four sedan fwd front 97.30 171.70 65.50 55.70 2264 ohc four 97 idi 3.01 3.40 23.00 52 4800 37 46 7995 +2 94 volkswagen gas std four sedan fwd front 97.30 171.70 65.50 55.70 2212 ohc four 109 mpfi 3.19 3.40 9.00 85 5250 27 34 8195 +2 94 volkswagen gas std four sedan fwd front 97.30 171.70 65.50 55.70 2275 ohc four 109 mpfi 3.19 3.40 9.00 85 5250 27 34 8495 +2 94 volkswagen diesel turbo four sedan fwd front 97.30 171.70 65.50 55.70 2319 ohc four 97 idi 3.01 3.40 23.00 68 4500 37 42 9495 +2 94 volkswagen gas std four sedan fwd front 97.30 171.70 65.50 55.70 2300 ohc four 109 mpfi 3.19 3.40 10.00 100 5500 26 32 9995 +3 ? volkswagen gas std two convertible fwd front 94.50 159.30 64.20 55.60 2254 ohc four 109 mpfi 3.19 3.40 8.50 90 5500 24 29 11595 +3 256 volkswagen gas std two hatchback fwd front 94.50 165.70 64.00 51.40 2221 ohc four 109 mpfi 3.19 3.40 8.50 90 5500 24 29 9980 +0 ? volkswagen gas std four sedan fwd front 100.40 180.20 66.90 55.10 2661 ohc five 136 mpfi 3.19 3.40 8.50 110 5500 19 24 13295 +0 ? volkswagen diesel turbo four sedan fwd front 100.40 180.20 66.90 55.10 2579 ohc four 97 idi 3.01 3.40 23.00 68 4500 33 38 13845 +0 ? volkswagen gas std four wagon fwd front 100.40 183.10 66.90 55.10 2563 ohc four 109 mpfi 3.19 3.40 9.00 88 5500 25 31 12290 +-2 103 volvo gas std four sedan rwd front 104.30 188.80 67.20 56.20 2912 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 23 28 12940 +-1 74 volvo gas std four wagon rwd front 104.30 188.80 67.20 57.50 3034 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 23 28 13415 +-2 103 volvo gas std four sedan rwd front 104.30 188.80 67.20 56.20 2935 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 24 28 15985 +-1 74 volvo gas std four wagon rwd front 104.30 188.80 67.20 57.50 3042 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 24 28 16515 +-2 103 volvo gas turbo four sedan rwd front 104.30 188.80 67.20 56.20 3045 ohc four 130 mpfi 3.62 3.15 7.50 162 5100 17 22 18420 +-1 74 volvo gas turbo four wagon rwd front 104.30 188.80 67.20 57.50 3157 ohc four 130 mpfi 3.62 3.15 7.50 162 5100 17 22 18950 +-1 95 volvo gas std four sedan rwd front 109.10 188.80 68.90 55.50 2952 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 23 28 16845 +-1 95 volvo gas turbo four sedan rwd front 109.10 188.80 68.80 55.50 3049 ohc four 141 mpfi 3.78 3.15 8.70 160 5300 19 25 19045 +-1 95 volvo gas std four sedan rwd front 109.10 188.80 68.90 55.50 3012 ohcv six 173 mpfi 3.58 2.87 8.80 134 5500 18 23 21485 +-1 95 volvo diesel turbo four sedan rwd front 109.10 188.80 68.90 55.50 3217 ohc six 145 idi 3.01 3.40 23.00 106 4800 26 27 22470 +-1 95 volvo gas turbo four sedan rwd front 109.10 188.80 68.90 55.50 3062 ohc four 141 mpfi 3.78 3.15 9.50 114 5400 19 25 22625 diff --git a/pyminer2/tests/datasets/invalid_characters.tab b/pyminer2/tests/datasets/invalid_characters.tab new file mode 100644 index 0000000000000000000000000000000000000000..b25ebc19c57fbfa0a3227c5b76e41c122713976f --- /dev/null +++ b/pyminer2/tests/datasets/invalid_characters.tab @@ -0,0 +1 @@ +davcna 2. OSNOVNA OLA SLOVENSKA BISTRICA s c meta 10304851 12.12 \ No newline at end of file diff --git a/pyminer2/tests/datasets/ionosphere.tab b/pyminer2/tests/datasets/ionosphere.tab new file mode 100644 index 0000000000000000000000000000000000000000..329abf64d582720f87188452b1935de75ddc19f1 --- /dev/null +++ b/pyminer2/tests/datasets/ionosphere.tab @@ -0,0 +1,354 @@ +a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 a23 a24 a25 a26 a27 a28 a29 a30 a31 a32 a33 a34 y +d d c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c d +i i class +1 0 0.99539 -0.05889 0.85243 0.02306 0.83398 -0.37708 1 0.03760 0.85243 -0.17755 0.59755 -0.44945 0.60536 -0.38223 0.84356 -0.38542 0.58212 -0.32192 0.56971 -0.29674 0.36946 -0.47357 0.56811 -0.51171 0.41078 -0.46168 0.21266 -0.34090 0.42267 -0.54487 0.18641 -0.45300 g +1 0 1 -0.18829 0.93035 -0.36156 -0.10868 -0.93597 1 -0.04549 0.50874 -0.67743 0.34432 -0.69707 -0.51685 -0.97515 0.05499 -0.62237 0.33109 -1 -0.13151 -0.45300 -0.18056 -0.35734 -0.20332 -0.26569 -0.20468 -0.18401 -0.19040 -0.11593 -0.16626 -0.06288 -0.13738 -0.02447 b +1 0 1 -0.03365 1 0.00485 1 -0.12062 0.88965 0.01198 0.73082 0.05346 0.85443 0.00827 0.54591 0.00299 0.83775 -0.13644 0.75535 -0.08540 0.70887 -0.27502 0.43385 -0.12062 0.57528 -0.40220 0.58984 -0.22145 0.43100 -0.17365 0.60436 -0.24180 0.56045 -0.38238 g +1 0 1 -0.45161 1 1 0.71216 -1 0 0 0 0 0 0 -1 0.14516 0.54094 -0.39330 -1 -0.54467 -0.69975 1 0 0 1 0.90695 0.51613 1 1 -0.20099 0.25682 1 -0.32382 1 b +1 0 1 -0.02401 0.94140 0.06531 0.92106 -0.23255 0.77152 -0.16399 0.52798 -0.20275 0.56409 -0.00712 0.34395 -0.27457 0.52940 -0.21780 0.45107 -0.17813 0.05982 -0.35575 0.02309 -0.52879 0.03286 -0.65158 0.13290 -0.53206 0.02431 -0.62197 -0.05707 -0.59573 -0.04608 -0.65697 g +1 0 0.02337 -0.00592 -0.09924 -0.11949 -0.00763 -0.11824 0.14706 0.06637 0.03786 -0.06302 0 0 -0.04572 -0.15540 -0.00343 -0.10196 -0.11575 -0.05414 0.01838 0.03669 0.01519 0.00888 0.03513 -0.01535 -0.03240 0.09223 -0.07859 0.00732 0 0 -0.00039 0.12011 b +1 0 0.97588 -0.10602 0.94601 -0.20800 0.92806 -0.28350 0.85996 -0.27342 0.79766 -0.47929 0.78225 -0.50764 0.74628 -0.61436 0.57945 -0.68086 0.37852 -0.73641 0.36324 -0.76562 0.31898 -0.79753 0.22792 -0.81634 0.13659 -0.82510 0.04606 -0.82395 -0.04262 -0.81318 -0.13832 -0.80975 g +0 0 0 0 0 0 1 -1 0 0 -1 -1 0 0 0 0 1 1 -1 -1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 b +1 0 0.96355 -0.07198 1 -0.14333 1 -0.21313 1 -0.36174 0.92570 -0.43569 0.94510 -0.40668 0.90392 -0.46381 0.98305 -0.35257 0.84537 -0.66020 0.75346 -0.60589 0.69637 -0.64225 0.85106 -0.65440 0.57577 -0.69712 0.25435 -0.63919 0.45114 -0.72779 0.38895 -0.73420 g +1 0 -0.01864 -0.08459 0 0 0 0 0.11470 -0.26810 -0.45663 -0.38172 0 0 -0.33656 0.38602 -0.37133 0.15018 0.63728 0.22115 0 0 0 0 -0.14803 -0.01326 0.20645 -0.02294 0 0 0.16595 0.24086 -0.08208 0.38065 b +1 0 1 0.06655 1 -0.18388 1 -0.27320 1 -0.43107 1 -0.41349 0.96232 -0.51874 0.90711 -0.59017 0.89230 -0.66474 0.69876 -0.70997 0.70645 -0.76320 0.63081 -0.80544 0.55867 -0.89128 0.47211 -0.86500 0.40303 -0.83675 0.30996 -0.89093 0.22995 -0.89158 g +1 0 1 -0.54210 1 -1 1 -1 1 0.36217 1 -0.41119 1 1 1 -1 1 -0.29354 1 -0.93599 1 1 1 1 1 -0.40888 1 -0.62745 1 -1 1 -1 1 -1 b +1 0 1 -0.16316 1 -0.10169 0.99999 -0.15197 1 -0.19277 0.94055 -0.35151 0.95735 -0.29785 0.93719 -0.34412 0.94486 -0.28106 0.90137 -0.43383 0.86043 -0.47308 0.82987 -0.51220 0.84080 -0.47137 0.76224 -0.58370 0.65723 -0.68794 0.68714 -0.64537 0.64727 -0.67226 g +1 0 1 -0.86701 1 0.22280 0.85492 -0.39896 1 -0.12090 1 0.35147 1 0.07772 1 -0.14767 1 -1 1 -1 0.61831 0.15803 1 0.62349 1 -0.17012 1 0.35924 1 -0.66494 1 0.88428 1 -0.18826 b +1 0 1 0.07380 1 0.03420 1 -0.05563 1 0.08764 1 0.19651 1 0.20328 1 0.12785 1 0.10561 1 0.27087 1 0.44758 1 0.41750 1 0.20033 1 0.36743 0.95603 0.48641 1 0.32492 1 0.46712 g +1 0 0.50932 -0.93996 1 0.26708 -0.03520 -1 1 -1 0.43685 -1 0 0 -1 -0.34265 -0.37681 0.03623 1 -1 0 0 0 0 -0.16253 0.92236 0.39752 0.26501 0 0 1 0.23188 0 0 b +1 0 0.99645 0.06468 1 -0.01236 0.97811 0.02498 0.96112 0.02312 0.99274 0.07808 0.89323 0.10346 0.94212 0.05269 0.88809 0.11120 0.86104 0.08631 0.81633 0.11830 0.83668 0.14442 0.81329 0.13412 0.79476 0.13638 0.79110 0.15379 0.77122 0.15930 0.70941 0.12015 g +0 0 0 0 -1 -1 1 1 -1 1 -1 1 1 -1 1 1 -1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 -1 1 -1 -1 1 -1 b +1 0 0.67065 0.02528 0.66626 0.05031 0.57197 0.18761 0.08776 0.34081 0.63621 0.12131 0.62099 0.14285 0.78637 0.10976 0.58373 0.18151 0.14395 0.41224 0.53888 0.21326 0.51420 0.22625 0.48838 0.23724 0.46167 0.24618 0.43433 0.25306 0.40663 0.25792 1 0.33036 g +0 0 1 -1 0 0 0 0 1 1 1 -1 -0.71875 1 0 0 -1 1 1 1 -1 1 1 0.56250 -1 1 1 1 1 -1 1 1 1 1 b +1 0 1 -0.00612 1 -0.09834 1 -0.07649 1 -0.10605 1 -0.11073 1 -0.39489 1 -0.15616 0.92124 -0.31884 0.86473 -0.34534 0.91693 -0.44072 0.96060 -0.46866 0.81874 -0.40372 0.82681 -0.42231 0.75784 -0.38231 0.80448 -0.40575 0.74354 -0.45039 g +0 0 1 1 0 0 0 0 -1 -1 0 0 0 0 -1 -1 -1 -1 -1 1 -1 1 0 0 0 0 1 -1 -1 1 -1 1 -1 1 b +1 0 0.96071 0.07088 1 0.04296 1 0.09313 0.90169 -0.05144 0.89263 0.02580 0.83250 -0.06142 0.87534 0.09831 0.76544 0.00280 0.75206 -0.05295 0.65961 -0.07905 0.64158 -0.05929 0.55677 -0.07705 0.58051 -0.02205 0.49664 -0.01251 0.51310 -0.00015 0.52099 -0.00182 g +0 0 -1 1 0 0 0 0 -1 1 1 1 0 0 0 0 1 -1 -1 1 1 1 0 0 -1 -1 1 -1 1 1 -1 1 0 0 b +1 0 1 -0.06182 1 0.02942 1 -0.05131 1 -0.01707 1 -0.11726 0.84493 -0.05202 0.93392 -0.06598 0.69170 -0.07379 0.65731 -0.20367 0.94910 -0.31558 0.80852 -0.31654 0.84932 -0.34838 0.72529 -0.29174 0.73094 -0.38576 0.54356 -0.26284 0.64207 -0.39487 g +1 0 1 0.57820 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -0.62796 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 b +1 0 1 -0.08714 1 -0.17263 0.86635 -0.81779 0.94817 0.61053 0.95473 -0.41382 0.88486 -0.31736 0.87937 -0.23433 0.81051 -0.62180 0.12245 -1 0.90284 0.11053 0.62357 -0.78547 0.55389 -0.82868 0.48136 -0.86583 0.40650 -0.89674 0.32984 -0.92128 -0.13341 -1 g +0 0 -1 -1 0 0 -1 1 1 -0.37500 0 0 0 0 0 0 1 -1 -1 -1 1 -1 0 0 1 -1 -1 1 -1 -1 0 0 -1 1 b +1 0 1 0.08380 1 0.17387 1 -0.13308 0.98172 0.64520 1 0.47904 1 0.59113 1 0.70758 1 0.82777 1 0.95099 1 1 0.98042 1 0.91624 1 0.83899 1 0.74822 1 0.64358 1 0.52479 1 g +0 0 -1 -1 1 1 1 -1 -1 1 1 -1 -1 -1 0 0 1 1 -1 -1 1 -1 1 -1 1 1 1 -1 1 -1 -1 1 1 -1 b +1 0 1 -0.14236 1 -0.16256 1 -0.23656 1 -0.07514 1 -0.25010 1 -0.26161 1 -0.21975 1 -0.38606 1 -0.46162 1 -0.35519 1 -0.59661 1 -0.47643 0.98820 -0.49687 1 -0.75820 1 -0.75761 1 -0.84437 g +1 0 1 -1 1 1 1 -1 1 -1 1 -1 1 -0.01840 1 -1 1 1 1 -0.85583 1 1 1 -1 0 0 1 1 1 -0.79141 1 1 1 1 b +1 0 0.88208 -0.14639 0.93408 -0.11057 0.92100 -0.16450 0.88307 -0.17036 0.88462 -0.31809 0.85269 -0.31463 0.82116 -0.35924 0.80681 -0.33632 0.75243 -0.47022 0.70555 -0.47153 0.66150 -0.50085 0.61297 -0.48086 0.56804 -0.54629 0.50179 -0.59854 0.47075 -0.57377 0.42189 -0.58086 g +1 0 0.71253 -0.02595 0.41287 -0.23067 0.98019 -0.09473 0.99709 -0.10236 1 -0.10951 0.58965 1 0.83726 -1 0.82270 -0.17863 0.80760 -0.28257 -0.25914 0.92730 0.51933 0.05456 0.65493 -0.20392 0.93124 -0.41307 0.63811 -0.21901 0.86136 -0.87354 -0.23186 -1 b +1 0 1 -0.15899 0.72314 0.27686 0.83443 -0.58388 1 -0.28207 1 -0.49863 0.79962 -0.12527 0.76837 0.14638 1 0.39337 1 0.26590 0.96354 -0.01891 0.92599 -0.91338 1 0.14803 1 -0.11582 1 -0.11129 1 0.53372 1 -0.57758 g +1 0 0.66161 -1 1 1 1 -0.67321 0.80893 -0.40446 1 -1 1 -0.89375 1 0.73393 0.17589 0.70982 1 0.78036 1 0.85268 1 -1 1 0.85357 1 -0.08571 0.95982 -0.36250 1 0.65268 1 0.34732 b +1 0 1 0.00433 1 -0.01209 1 -0.02960 1 -0.07014 0.97839 -0.06256 1 -0.06544 0.97261 -0.07917 0.92561 -0.13665 0.94184 -0.14327 0.99589 -0.14248 0.94815 -0.13565 0.89469 -0.20851 0.89067 -0.17909 0.85644 -0.18552 0.83777 -0.20101 0.83867 -0.20766 g +0 0 1 1 1 -1 0 0 0 0 -1 -1 0 0 0 0 -1 1 1 1 -1 1 -1 1 1 -1 1 1 -1 1 1 1 0 0 b +1 0 0.91241 0.04347 0.94191 0.02280 0.94705 0.05345 0.93582 0.01321 0.91911 0.06348 0.92766 0.12067 0.92048 0.06211 0.88899 0.12722 0.83744 0.14439 0.80983 0.11849 0.77041 0.14222 0.75755 0.11299 0.73550 0.13282 0.66387 0.15300 0.70925 0.10754 0.65258 0.11447 g +1 0 1 0.02461 0.99672 0.04861 0.97545 0.07143 0.61745 -1 0.91036 0.11147 0.88462 0.53640 0.82077 0.14137 0.76929 0.15189 1 0.41003 0.65850 0.16371 0.60138 0.16516 0.54446 0.16390 0.48867 0.16019 0.43481 0.15436 0.38352 0.14677 1 1 b +1 0 1 0.06538 1 0.20746 1 0.26281 0.93051 0.32213 0.86773 0.39039 0.75474 0.50082 0.79555 0.52321 0.65954 0.60756 0.57619 0.62999 0.47807 0.67135 0.40553 0.68840 0.34384 0.72082 0.27712 0.72386 0.19296 0.70682 0.11372 0.72688 0.06990 0.71444 g +1 0 -1 -1 1 1 1 -0.14375 0 0 -1 1 1 1 0.17917 -1 -1 -1 0.08750 -1 1 -1 -1 1 -1 -1 1 -1 -1 -1 1 1 0 0 b +1 0 0.90932 0.08791 0.86528 0.16888 1 0.16598 0.55187 0.68154 0.70207 0.36719 0.16286 0.42739 0.57620 0.46086 0.51067 0.49618 0.31639 0.12967 0.37824 0.54462 0.31274 0.55826 0.24856 0.56527 0.18626 0.56605 0.12635 0.56101 0.06927 0.55061 0.12137 0.67739 g +1 0 -0.64286 -1 1 0.82857 1 -1 1 -0.23393 1 0.96161 1 -0.37679 1 -1 1 0.13839 1 -1 1 -0.03393 -0.84286 1 0.53750 0.85714 1 1 1 -1 1 -1 1 -1 b +1 0 0.99025 -0.05785 0.99793 -0.13009 0.98663 -0.19430 0.99374 -0.25843 0.92738 -0.30130 0.92651 -0.37965 0.89812 -0.43796 0.84922 -0.52064 0.87433 -0.57075 0.79016 -0.59839 0.74725 -0.64615 0.68282 -0.68479 0.65247 -0.73174 0.61010 -0.75353 0.54752 -0.80278 0.49195 -0.83245 g +0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 -0.37500 -1 -1 -1 0 0 0 0 -1 -1 -1 -1 -1 1 1 0 0 0 b +1 0 1 -0.03730 1 -0.07383 0.99601 -0.11039 0.99838 -0.09931 0.98941 -0.13814 0.96674 -0.21695 0.95288 -0.25099 0.91236 -0.34400 0.90581 -0.32152 0.89991 -0.34691 0.87874 -0.37643 0.86213 -0.42990 0.83172 -0.43122 0.81433 -0.42593 0.77919 -0.47977 0.75115 -0.50152 g +1 0 0.94598 -0.02685 -1 0.26131 -0.36393 0.35639 0.69258 -0.63427 1 -0.03353 -0.29020 -0.00550 -0.54852 0.15452 0.91921 -0.46270 1 -0.50424 -0.29735 -0.31454 -0.73864 0.37361 0.83872 -0.46734 0.52208 -0.58130 1 -0.61393 -0.09634 0.20477 -0.06117 0.41913 b +1 0 0.98166 0.00874 0.98103 -0.03818 0.97565 -0.05699 0.95947 -0.06971 0.99004 -0.04507 0.94713 -0.11102 0.93369 -0.12790 0.94217 -0.11583 0.79682 -0.19200 0.88274 -0.17387 0.86257 -0.18739 0.88487 -0.19689 0.81813 -0.21136 0.78546 -0.23864 0.76911 -0.23095 0.74323 -0.23902 g +1 0 0 0 1 0.51724 0 0 0.10991 -1 0 0 0 0 -1 -0.22414 -0.55711 -0.83297 0.76940 0.63147 0 0 0.53448 0.35668 -0.90302 0.44828 1 -1 -1 0.81573 0 0 0 0 b +1 0 0.84134 -0.18362 0.43644 0.02919 0.93421 -0.00267 0.87947 0.13795 0.81121 -0.01789 0.88559 0.54991 0.91714 -0.57486 0.75000 -0.29520 0.86676 -0.20104 1 1 0.46610 -0.16290 0.90066 -0.02778 0.93358 -0.01158 0.61582 -0.32298 0.84463 -0.25706 0.93323 -0.01425 g +0 0 1 1 1 -1 0 0 0 0 1 1 1 1 -1 -1 1 -1 -1 1 0 0 1 -1 1 -1 1 1 -1 -1 0 0 0 0 b +1 0 1 1 1 1 0.91010 1 -0.26970 1 -0.83152 1 -1 1 -1 0.72526 -1 -0.57779 -1 -0.42052 -1 -1 -0.52838 -1 0.90014 -1 1 -1 1 -1 1 -0.34686 1 0.34845 g +1 0 -0.67935 -1 -1 1 1 0.63317 0.03515 -1 -1 -1 1 1 0.88683 -1 -1 1 0.83840 1 1 -1 -1 -1 -0.18856 1 1 -1 -1 -1 -1 1 1 0.33611 b +1 0 0.95659 0.08143 0.97487 -0.05667 0.97165 -0.08484 0.96097 -0.06561 0.94717 0.01279 0.95436 -0.16795 0.94612 -0.19497 0.99630 -0.32268 0.90343 -0.35902 0.91428 -0.27316 0.90140 -0.29807 0.99899 -0.40747 0.87244 -0.34586 0.92059 -0.30619 0.83951 -0.39061 0.82166 -0.41173 g +1 0 0.08333 -0.20685 -1 1 -1 1 0.71875 0.47173 -0.82143 -0.62723 -1 -1 -1 1 -0.02753 0.59152 -0.42113 -0.42113 -0.74628 -1 -1 -0.46801 -1 0.23810 1 -1 -1 -0.38914 -1 -1 -1 0.61458 b +1 0 1 -0.02259 1 -0.04494 1 -0.06682 1 -0.08799 1 0.56173 1 -0.12738 1 -0.14522 1 0.32407 1 -0.17639 0.99484 -0.18949 0.95601 -0.20081 1 -0.92284 0.87280 -0.21793 0.82920 -0.22370 0.78479 -0.22765 0.73992 -0.22981 g +0 0 -1 1 1 -1 -1 1 0 0 1 1 -1 -0.18750 1 1 -1 -1 1 -1 -1 -1 1 1 1 -1 1 1 1 1 0 0 -1 -1 b +1 0 1 0.05812 0.94525 0.07418 0.99952 0.13231 1 -0.01911 0.94846 0.07033 0.95713 0.14644 0.94862 0.11224 0.90896 0.20119 0.96741 0.16265 0.99695 0.14258 0.90784 0.16410 0.91667 0.22431 0.88423 0.23571 0.88568 0.22511 0.78324 0.29576 0.83574 0.31166 g +1 0 0.17188 -1 -1 1 0 0 0 0 -1 1 0 0 -0.61354 -0.67708 0.80521 0.36146 0.51979 0.14375 0 0 -1 -0.27083 -0.84792 0.96250 1 1 -1 0.67708 0 0 0 0 b +1 0 1 0.09771 1 0.12197 1 0.22574 0.98602 0.09237 0.94930 0.19211 0.92992 0.24288 0.89241 0.28343 0.85529 0.26721 0.83656 0.33129 0.83393 0.31698 0.74829 0.39597 0.76193 0.34658 0.68452 0.42746 0.62764 0.46031 0.56791 0.47033 0.54252 0.50903 g +1 0 0.01667 -0.35625 0 0 0 0 0 0 0 0 0 0 0.12292 -0.55000 0.22813 0.82813 1 -0.42292 0 0 0.08333 -1 -0.10625 -0.16667 1 -0.76667 -1 0.18854 0 0 1 -0.27292 b +1 0 1 0.16801 0.99352 0.16334 0.94616 0.33347 0.91759 0.22610 0.91408 0.37107 0.84250 0.46899 0.81011 0.49225 0.78473 0.48311 0.65091 0.56977 0.56553 0.58071 0.55586 0.64720 0.48311 0.55236 0.43317 0.69129 0.35684 0.76147 0.33921 0.66844 0.22101 0.78685 g +1 0 0.63816 1 0.20833 -1 1 1 0.87719 0.30921 -0.66886 1 -0.05921 0.58772 0.01754 0.05044 -0.51535 -1 0.14254 -0.03289 0.32675 -0.43860 -1 1 0.80921 -1 1 -0.06140 1 1 0.20614 -1 1 1 b +1 0 1 -0.41457 1 0.76131 0.87060 0.18593 1 -0.09925 0.93844 0.47990 0.65452 -0.16080 1 0.00879 0.97613 -0.50126 0.80025 -0.24497 0.88065 -0.19095 1 -0.12312 0.93593 0.10678 0.92890 -0.07249 1 -0.27387 0.43970 0.19849 0.51382 -0.05402 g +1 0 0.84783 0.10598 1 0.39130 1 -1 0.66938 0.08424 1 0.27038 1 0.60598 1 0.35507 1 0.02672 0.58424 -0.43025 1 0.63496 0.89130 0.26585 0.91033 -0.33333 1 0.15942 0.37681 -0.01947 1 0.22464 1 0.37409 b +1 0 1 0.28046 1 0.02477 1 0.07764 1 0.04317 0.98762 0.33266 1 0.05489 1 0.04384 0.95750 -0.24598 0.84371 -0.08668 1 0.04150 0.99933 0.27376 1 -0.39056 0.96414 -0.02174 0.86747 0.23360 0.94578 -0.22021 0.80355 -0.07329 g +0 0 1 -1 1 -1 1 -1 1 -1 1 1 1 1 1 -1 1 1 1 1 1 1 1 -1 1 -1 1 -1 1 0.65625 0 0 1 -1 b +1 0 1 0.67784 0.81309 0.82021 0.43019 1 0.20619 0.80541 -0.43872 1 -0.79135 0.77092 -1 0.40268 -0.39046 -0.58634 -0.97907 -0.42822 -0.73083 -0.76339 -0.37671 -0.97491 0.41366 -1 0.41778 -0.93296 0.25773 -1 0.93570 -0.35222 0.98816 0.03446 g +1 0 1 1 1 -1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 0.5 0 0 1 -1 1 -1 b +1 0 1 0.03529 1 0.18281 1 0.26968 1 0.25068 1 0.28778 1 0.38643 1 0.31674 1 0.65701 1 0.53846 1 0.61267 1 0.59457 0.89593 0.68326 0.89502 0.71374 0.85611 0.67149 0.74389 0.85611 0.71493 0.75837 g +0 0 1 -1 1 1 -1 -1 1 -1 0 0 0 0 -1 1 1 -1 1 -1 -0.75000 1 1 -1 1 -1 1 -1 -1 -1 0 0 1 -1 b +1 0 0.96087 0.08620 0.96760 0.19279 0.96026 0.27451 0.98044 0.35052 0.92867 0.46281 0.86265 0.52517 0.82820 0.58794 0.73242 0.69065 0.69003 0.73140 0.54473 0.68820 0.48339 0.76197 0.40615 0.74689 0.33401 0.83796 0.24944 0.86061 0.13756 0.86835 0.09048 0.86285 g +1 0 0.69444 0.38889 0 0 -0.32937 0.69841 0 0 0 0 0 0 0.20635 -0.24206 0.21032 0.19444 0.46429 0.78175 0 0 0 0 0.73413 0.27381 0.76190 0.63492 0 0 0 0 0 0 b +1 0 1 0.05070 1 0.10827 1 0.19498 1 0.28453 1 0.34826 1 0.38261 0.94575 0.42881 0.89126 0.50391 0.75906 0.58801 0.80644 0.59962 0.79578 0.62758 0.66643 0.63942 0.59417 0.69435 0.49538 0.72684 0.47027 0.71689 0.33381 0.75243 g +0 0 1 1 0 0 1 -1 1 -1 1 1 1 1 1 -1 1 1 1 1 1 -1 -1 -1 1 -1 1 -1 1 1 0 0 1 -1 b +1 0 1 0.04078 1 0.11982 1 0.16159 1 0.27921 0.98703 0.30889 0.92745 0.37639 0.91118 0.39749 0.81939 0.46059 0.78619 0.46994 0.79400 0.56282 0.70331 0.58129 0.67077 0.59723 0.58903 0.60990 0.53952 0.60932 0.45312 0.63636 0.40442 0.62658 g +0 0 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 -1 -1 1 -1 1 -1 1 1 -1 1 1 -1 1 -1 -1 -1 1 b +1 0 1 0.24168 1 0.48590 1 0.72973 1 1 1 1 1 1 1 0.77128 1 1 1 1 0.74468 1 0.89647 1 0.64628 1 0.38255 1 0.10819 1 -0.17370 1 -0.81383 1 g +0 0 1 1 1 -1 1 1 -1 1 0 0 1 1 0 0 0 0 -1 1 -1 1 1 1 1 -1 1 1 1 1 1 -1 -1 1 b +1 0 1 -0.06604 1 0.62937 1 0.09557 1 0.20280 1 -1 1 -0.40559 1 -0.15851 1 0.04895 1 -0.61538 1 -0.26573 1 -1 1 -0.58042 1 -0.81372 1 -1 1 -0.78555 1 -0.48252 g +0 0 1 -1 1 1 1 1 1 1 1 1 1 -1 1 -1 1 1 1 -1 1 1 1 1 1 -1 1 1 1 -1 1 1 1 -1 b +1 0 0.92277 0.07804 0.92679 0.16251 0.89702 0.24618 0.84111 0.35197 0.78801 0.42196 0.70716 0.46983 0.70796 0.56476 0.60459 0.64200 0.51247 0.64924 0.39903 0.66975 0.34232 0.68343 0.23693 0.76146 0.18765 0.73885 0.09694 0.71038 0.02735 0.77072 -0.04023 0.69509 g +1 0 0.68198 -0.17314 0.82332 0.21908 0.46643 0.32862 0.25795 0.58304 1 -0.15194 0.01060 0.44523 0.01060 0.38869 0.18681 0.41168 0.10567 0.36353 0.04325 0.30745 -0.00083 0.24936 -0.02862 0.19405 -0.04314 0.14481 -0.04779 0.10349 -0.04585 0.07064 -0.04013 0.04586 b +1 0 0.74852 -0.02811 0.65680 -0.05178 0.80621 0.02811 0.85947 0.02515 0.63462 0.08728 0.71598 0.07840 0.73077 0.05178 0.78550 -0.27811 0.65976 -0.01479 0.78698 0.06953 0.34615 -0.18639 0.65385 0.02811 0.61009 -0.06637 0.53550 -0.21154 0.59024 -0.14053 0.56361 0.02959 g +1 0 0.39179 -0.06343 0.97464 0.04328 1 1 0.35821 0.15299 0.54478 0.13060 0.61567 -0.82090 0.57836 0.67910 0.66791 -0.10448 0.46642 -0.11567 0.65574 0.14792 0.83209 0.45522 0.47015 0.16418 0.49309 0.14630 0.32463 -0.02612 0.39118 0.13521 0.34411 0.12755 b +1 0 0.67547 0.04528 0.76981 -0.10566 0.77358 0.03774 0.66038 -0.04528 0.64528 0.01132 0.66792 -0.13962 0.72075 -0.02264 0.76981 0.08679 0.61887 -0.07925 0.75849 -0.23774 0.73962 -0.14717 0.84906 -0.15094 0.73886 -0.05801 0.66792 0.02264 0.86415 0.03774 0.73208 0.00755 g +1 0 0.72727 -0.05000 0.89241 0.03462 1 0.72727 0.66364 -0.05909 0.48182 -0.16818 0.81809 0.09559 0.56818 1 0.50455 0.21818 0.66818 0.10000 1 -0.30000 0.98636 -1 0.57273 0.32727 0.56982 0.14673 0.42273 0.08182 0.48927 0.14643 1 1 b +1 0 0.57647 -0.01569 0.40392 0 0.38431 0.12941 0.40000 -0.05882 0.56471 0.14118 0.46667 0.08235 0.52549 -0.05490 0.58039 0.01569 0.50196 0 0.45882 0.06667 0.58039 0.08235 0.49804 0.00392 0.48601 0.10039 0.46275 0.08235 0.45098 0.23529 0.43137 0.17255 g +1 0 0.41932 0.12482 0.35000 0.12500 0.23182 0.27955 -0.03636 0.44318 0.04517 0.36194 -0.19091 0.33636 -0.13350 0.27322 0.02727 0.40455 -0.34773 0.12727 -0.20028 0.05078 -0.18636 0.36364 -0.14003 -0.04802 -0.09971 -0.07114 -1 -1 -0.02916 -0.07464 -0.00526 -0.06314 b +1 0 0.88305 -0.21996 1 0.36373 0.82403 0.19206 0.85086 0.05901 0.90558 -0.04292 0.85193 0.25000 0.77897 0.25322 0.69206 0.57940 0.71030 0.39056 0.73176 0.27575 1 0.34871 0.56760 0.52039 0.69811 0.53235 0.80901 0.58584 0.43026 0.70923 0.52361 0.54185 g +1 0 0.84557 -0.08580 -0.31745 -0.80553 -0.08961 -0.56435 0.80648 0.04576 0.89514 -0.00763 -0.18494 0.63966 -0.20019 -0.68065 0.85701 -0.11344 0.77979 -0.15729 -0.06959 0.50810 -0.34128 0.80934 0.78932 -0.03718 0.70882 -0.25288 0.77884 -0.14109 -0.21354 -0.78170 -0.18494 -0.59867 b +1 0 0.70870 -0.24783 0.64348 0.04348 0.45217 0.38261 0.65217 0.18261 0.5 0.26957 0.57826 -0.23043 0.50435 0.37826 0.38696 -0.42609 0.36087 -0.26087 0.26957 0.11739 0.53246 -0.03845 0.31304 -0.12174 0.49930 -0.04264 0.48348 -0.04448 0.64348 -0.25217 0.50435 0.14783 g +1 0 -0.54180 0.14861 -0.33746 0.73375 0.52012 -0.13932 0.31889 -0.06811 0.20743 -0.15170 0.47368 0.08978 0.56347 -0.15480 0.16409 0.45201 0.33746 0.03406 0.50464 0.07121 -0.63777 -0.61610 1 0.65635 0.41348 -0.40116 -0.15170 0.11146 0.02399 0.55820 0.52632 -0.08978 b +1 0 0.29202 0.13582 0.45331 0.16808 0.51783 -0.00509 0.52632 0.20883 0.52462 -0.16638 0.47368 -0.04754 0.55518 0.03905 0.81664 -0.22411 0.42445 -0.04244 0.34975 0.06621 0.28183 -0.20883 0.51731 -0.03176 0.50369 -0.03351 0.34635 0.09847 0.70798 -0.01868 0.39559 -0.03226 g +1 0 0.79157 0.16851 0 0 0.56541 0.06874 0.39468 1 0.38359 0.99557 -0.02439 0.53215 0.23725 0.12860 -0.02661 0.95122 -0.50998 0.84922 -0.10200 0.38803 -0.42572 0.23725 -0.91574 0.80710 -0.34146 0.88248 -1 0.69401 -1 0.12860 0 0 b +1 0 0.90116 0.16607 0.79299 0.37379 0.72990 0.50515 0.59784 0.72997 0.44303 0.81152 0.24412 0.87493 0.06438 0.85038 -0.12611 0.87396 -0.28739 0.79617 -0.46635 0.65924 -0.57135 0.53805 -0.68159 0.39951 -0.71844 0.25835 -0.72369 0.11218 -0.71475 -0.05525 -0.67699 -0.19904 g +1 0 0.97714 0.19049 0.82683 0.46259 0.71771 0.58732 0.47968 0.84278 0.31409 0.92643 0.10289 0.93945 -0.13254 0.84290 -0.32020 0.91624 -0.52145 0.79525 -0.68274 0.49508 -0.77408 0.33537 -0.85376 0.17849 -0.83314 -0.01358 -0.82366 -0.19321 -0.67289 -0.33662 -0.59943 -0.49700 g +1 0 -1 -1 0 0 0.50814 -0.78502 0.60586 0.32899 -1 -0.41368 0 0 0 0 1 -0.26710 0.36482 -0.63518 0.97068 -1 -1 -1 1 -0.59609 -1 -1 -1 -1 1 -1 0 0 b +1 0 0.74084 0.04974 0.79074 0.02543 0.78575 0.03793 0.66230 0.09948 0.67801 0.31152 0.75934 0.07348 0.74695 0.08442 0.70681 -0.07853 0.63613 0 0.70021 0.11355 0.68183 0.12185 0.67016 0.15445 0.64158 0.13608 0.65707 0.17539 0.59759 0.14697 0.57455 0.15114 g +1 0 1 -1 0 0 0.77941 -0.99265 0.80882 0.55147 -0.41912 -0.94853 0 0 0 0 0.72059 -0.77206 0.73529 -0.60294 0 0 0.18382 -1 -1 -1 -1 -1 1 -1 1 -1 0 0 b +1 0 1 0.01709 0.96215 -0.03142 1 -0.03436 1 -0.05071 0.99026 -0.07092 0.99173 -0.09002 1 -0.15727 1 -0.14257 0.98310 -0.11813 1 -0.18519 1 -0.19272 0.98971 -0.22083 0.96490 -0.20243 0.94599 -0.17123 0.96436 -0.22561 0.87011 -0.23296 g +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 b +1 0 0.95704 -0.12095 0.63318 -0.12690 0.96365 -0.18242 0.97026 0.08460 0.92003 -0.01124 0.83543 -0.24719 1 -0.31395 0.99273 -0.21216 0.98678 -0.21018 1 -0.27165 0.93126 -0.39458 1 -0.19233 0.88793 -0.31565 0.81428 -0.23728 0.89095 -0.31857 0.69531 -0.41573 g +1 0 0.28409 -0.31818 0 0 0.68182 -1 0.30682 0.95833 0.64394 0.06439 0.34848 -0.84848 0 0 0.59091 -0.35985 0.45076 -0.80682 0 0 0 0 0.24242 0.17803 1 -0.23864 0.06061 -0.48485 0.16288 -0.70076 0 0 b +1 0 0.94490 -0.49311 1 -0.03692 0.98898 -0.87052 0.90083 0.66942 1 -0.10104 1 -0.12493 1 -0.15017 1 -0.17681 1 -0.20491 1 -0.23452 1 -0.26571 1 -0.29852 1 -0.33304 1 -0.36931 1 -0.40740 1 -0.44739 g +1 0 0 0 0 0 0 0 0 0 0.62195 1 0 0 0 0 0.36585 -0.71951 0.56098 -1 0 0 0 0 0 0 1 0.10976 0 0 0 0 0 0 b +1 0 0.99449 0.00526 0.84082 -0.11313 0.88237 -0.16431 0.99061 -0.06257 0.96484 -0.07496 0.85221 0.02966 0.87161 -0.20848 0.93881 -0.12977 0.98298 -0.08935 0.89876 0.00075 0.87836 -0.05882 0.93368 -0.19872 0.87579 -0.17806 0.94294 -0.16581 0.80253 -0.25741 0.76586 -0.27794 g +1 0 0.10135 0.10811 0 0 0 0 0.54730 0.82432 0.31081 1 0 0 0 0 0.37162 -1 0.33108 -1 0 0 0 0 -0.42568 -1 1 -1 0.55405 -0.23649 0 0 0 0 b +1 0 1 -0.57224 0.99150 -0.73371 0.89518 -0.97450 1 -0.35818 1 -0.23229 0.62890 -0.86402 1 -0.57535 1 -0.79603 0.76771 -0.88952 0.96601 -1 0.70120 -0.74896 0.61946 -0.76904 0.53777 -0.77986 0.81020 -1 1 -1 0.30445 -0.76112 g +1 0 0.65909 -0.62879 0 0 0 0 0.77273 1 1 -0.28030 0 0 0 0 0.62121 -0.22727 0.84091 -1 1 -1 0 0 0 0 1 -0.93939 -0.12879 -0.93182 0 0 0 0 b +1 0 0.86284 0.19310 0.80920 0.41149 0.67203 0.55785 0.54559 0.69962 0.36705 0.81533 0.19617 0.85671 -0.04061 0.86284 -0.17241 0.75785 -0.34100 0.65747 -0.48199 0.56092 -0.60230 0.40996 -0.59234 0.25747 -0.63038 0.08818 -0.57241 -0.07816 -0.54866 -0.19923 -0.42912 -0.31954 g +1 0 0.42000 -0.61000 0 0 1 -1 0.90000 1 0.43000 0.64000 0 0 0 0 0.67000 -0.29000 0.84000 -1 0 0 0 0 0.21000 0.68000 1 0.22000 0 0 0 0 0 0 b +1 0 1 0.23395 0.91404 0.52013 0.78020 0.72144 0.47660 0.84222 0.27639 0.91730 0.09467 0.88248 -0.21980 0.91404 -0.34168 0.75517 -0.51360 0.64527 -0.64527 0.44614 -0.74102 0.29162 -0.70838 0.03591 -0.71731 -0.11943 -0.64962 -0.28183 -0.51251 -0.44505 -0.37432 -0.53319 g +1 0 0.91353 0.81586 -0.72973 1 -0.39466 0.55735 0.05405 0.29730 -0.18599 -0.10241 -0.03158 -0.08970 0.01401 -0.03403 0.01108 -0.00537 0.00342 0.00097 0.00048 0.00075 -0.00003 0.00019 -0.00003 0.00002 -0.00001 0 0 0 0 0 0 0 b +1 0 0.21429 -0.09524 0.33333 0.07143 0.19048 0.19048 0.23810 0.09524 0.40476 0.02381 0.30952 -0.04762 0.30952 -0.04762 0.28571 -0.11905 0.33333 0.04762 0.30952 0 0.21429 -0.11905 0.35714 -0.04762 0.22109 -0.02290 0.19048 0 0.16997 -0.02034 0.14694 -0.01877 g +1 0 1 -0.14754 1 0.04918 0.57377 -0.01639 0.65574 0.01639 0.85246 -0.03279 0.72131 0 0.68852 -0.16393 0.19672 -0.14754 0.65558 -0.17176 0.67213 0.03279 1 -0.29508 0.31148 -0.34426 0.52385 -0.20325 0.32787 -0.03279 0.27869 -0.44262 0.49180 -0.06557 b +1 0 0.98182 0 0.88627 0.03131 0.86249 0.04572 0.80000 0 0.69091 0.04545 0.79343 0.08436 0.77118 0.09579 0.62727 0.25455 0.68182 0.12727 0.70674 0.12608 0.68604 0.13493 0.74545 0.22727 0.64581 0.15088 0.67273 0.02727 0.60715 0.16465 0.58840 0.17077 g +1 0 0.39286 0.52381 -0.78824 0.11342 -0.16628 -0.76378 0.66667 0.01190 0.82143 0.40476 -0.67230 0.30729 -0.34797 -0.63668 0.46429 0.15476 0.54762 0.05952 -0.51830 0.44961 -0.47651 -0.47594 0.32143 0.70238 0.51971 0.38848 0.57143 0.39286 -0.54891 -0.29915 0.25441 -0.55837 b +1 0 0.86889 -0.07111 1 -0.02494 1 -0.06889 0.87778 0.00222 0.83556 -0.06444 1 -0.07287 1 -0.20000 0.86889 0.05333 0.88000 -0.03778 1 -0.11526 1 -0.18667 0.84444 0.03556 1 -0.14162 0.82222 -0.14667 1 -0.15609 1 -0.44222 g +1 0 0.43636 -0.12727 0.58182 -0.14545 0.18182 -0.67273 0.34545 -0.03636 0.29091 -0.05455 0.29091 0.29091 0.36364 -0.41818 0.20000 -0.01818 0.36364 0.05455 0.12727 0.49091 0.61818 0.16364 0.32727 0.16364 0.41098 -0.07027 0.34545 -0.05455 0.12727 -0.36364 0.29091 -0.29091 b +1 0 1 -0.92453 1 0.75472 0.49057 -0.05660 0.62264 0 1 -0.00054 0.45283 0.07547 0.62264 -0.05660 0.98878 -0.00085 0.52830 0 0.52830 0.07547 0.95190 -0.00112 1 0.79245 0.92192 -0.00128 0.94340 -1 1 0.43396 0.43396 -0.11321 g +1 0 0.73810 0.83333 -0.76190 -0.23810 0.33333 -0.14286 0.45238 -0.14286 -0.67285 0.12808 0.33333 0 0.28571 -0.07143 -0.38214 0.51163 0.23810 0.02381 0.45238 0.04762 0.16667 -0.26190 -0.57255 -0.10234 0.24889 -0.51079 1 0 -0.66667 -0.04762 0.26190 0.02381 b +1 0 0.43750 0.04167 0.58333 -0.10417 0.39583 0 0.33333 -0.06250 0.47917 0 0.29167 0.10417 0.54167 0.02083 0.43750 -0.22917 0.35417 -0.22917 0.33333 0.08333 0.25000 0.18750 0.39583 -0.18750 0.44012 -0.10064 0.41667 -0.08333 0.58333 -0.31250 0.33333 -0.06250 g +1 0 1 1 0 0 0 0 0 0 0.47744 -0.89098 -0.51504 0.45489 -0.95489 0.28571 0.64662 1 0 0 0 0 0.62030 0.20301 -1 -1 1 -1 1 1 0 0 0 0 b +1 0 0.95217 0.06595 0.93614 0.13030 0.90996 0.19152 0.84881 -0.49962 0.90023 0.61320 0.77937 0.34328 0.72254 0.37988 0.66145 0.40844 0.95472 0.59862 0.53258 0.44088 0.46773 0.44511 0.40440 0.44199 0.34374 0.43221 0.90330 1 0.23405 0.39620 0.18632 0.37191 g +1 0 0.59840 0.40332 0.82809 0.80521 0.76001 0.70709 0.84010 -0.10984 0.97311 0.07981 0.95824 -0.85727 0.91962 0.88444 0.95452 -0.05206 0.88673 0.18135 0.98484 -0.69594 0.86670 -0.85755 0.28604 -0.30063 1 0.17076 0.62958 0.42677 0.87757 0.81007 0.81979 0.68822 b +1 0 0.95882 0.10129 1 -0.01918 0.98313 0.02555 0.96974 -0.09316 0.98955 -0.02716 0.97980 -0.03096 1 -0.05343 1 -0.05179 0.93840 0.01557 0.97620 -0.09284 0.97889 -0.05318 0.91567 -0.15675 0.95677 -0.06995 0.90978 0.01307 1 -0.10797 0.93144 -0.06888 g +1 0 0 0 -0.33672 0.85388 0 0 0.68869 -1 0.97078 0.31385 -0.26048 -0.59212 -0.30241 0.65565 0.94155 0.16391 0 0 0 0 -0.18043 -1 0 0 1 -1 0 0 0.04447 0.61881 0 0 b +1 0 0.96933 0.00876 1 0.00843 0.98658 -0.00763 0.97868 -0.02844 0.99820 -0.03510 1 -0.01271 1 -0.02581 1 -0.01175 0.98485 0.00025 1 -0.02612 1 -0.04744 0.96019 -0.04527 0.99188 -0.03473 0.97020 -0.02478 1 -0.03855 0.98420 -0.04112 g +1 0 0 0 0.98919 -0.22703 0.18919 -0.05405 0 0 0.93243 0.07297 1 -0.20000 1 0.07027 1 -0.11351 0 0 1 -0.21081 1 -0.41622 0 0 1 -0.17568 0 0 1 -0.25946 0.28919 -0.15676 b +1 0 0.64122 0.01403 0.34146 -0.02439 0.52751 0.03466 0.19512 0.12195 0.43313 0.04755 0.21951 0.04878 0.29268 0 0.36585 0 0.31707 0.07317 0.26829 0.12195 0.23698 0.05813 0.21951 0.09756 0.19304 0.05641 0.17410 0.05504 0.19512 0 0.17073 0.07317 g +1 0 1 1 1 -1 0 0 0 0 1 1 1 -1 1 1 1 -1 0 0 0 0 1 -0.27778 0 0 1 -1 1 1 1 -1 0 0 b +1 0 0.34694 0.20408 0.46939 0.24490 0.40816 0.20408 0.46939 0.44898 0.30612 0.59184 0.12245 0.55102 0 0.51020 -0.06122 0.55102 -0.20408 0.55102 -0.28571 0.44898 -0.28571 0.32653 -0.61224 0.22449 -0.46579 0.14895 -0.59184 0.18367 -0.34694 0 -0.26531 -0.24490 g +1 0 0 0 1 -1 0 0 0 0 1 1 1 -0.25342 1 0.23288 1 -1 0 0 0 0 1 1 0 0 1 -1 0 0 1 -1 0 0 b +1 0 0.89706 0.38235 0.91176 0.37500 0.74265 0.67647 0.45588 0.77941 0.19118 0.88971 -0.02206 0.86029 -0.20588 0.82353 -0.37500 0.67647 -0.5 0.47794 -0.73529 0.38235 -0.86029 0.08824 -0.74265 -0.12500 -0.67925 -0.24131 -0.55147 -0.42647 -0.44118 -0.50735 -0.28676 -0.56618 g +1 0 -1 0.28105 0.22222 0.15033 -0.75693 -0.70984 -0.30719 0.71242 -1 1 -0.81699 0.33987 -0.79085 -0.02614 -0.98039 -0.83007 -0.60131 -0.54248 -0.04575 -0.83007 0.94118 -0.94118 -1 -0.43137 0.74385 0.09176 -1 0.05229 0.18301 0.02614 -0.40201 -0.48241 b +1 0 0.26667 -0.10000 0.53333 0 0.33333 -0.13333 0.36667 0.11667 0.56667 0.01667 0.71667 0.08333 0.70000 -0.06667 0.53333 0.20000 0.41667 -0.01667 0.31667 0.20000 0.70000 0 0.25000 0.13333 0.46214 0.05439 0.40000 0.03333 0.46667 0.03333 0.41667 -0.05000 g +1 0 -0.26667 0.40000 -0.27303 0.12159 -0.17778 -0.04444 0.06192 -0.06879 0.04461 0.02575 -0.00885 0.02726 -0.01586 -0.00166 -0.00093 -0.00883 0.00470 -0.00153 0.00138 0.00238 -0.00114 0.00102 -0.00069 -0.00050 0.00019 -0.00043 0.00026 0.00005 0 0.00015 -0.00008 0.00002 b +1 0 1 -0.37838 0.64865 0.29730 0.64865 -0.24324 0.86486 0.18919 1 -0.27027 0.51351 0 0.62162 -0.05405 0.32432 -0.21622 0.71833 -0.17666 0.62162 0.05405 0.75676 0.13514 0.35135 -0.29730 0.61031 -0.22163 0.58478 -0.23027 0.72973 -0.59459 0.51351 -0.24324 g +1 0 0.94531 -0.03516 -1 -0.33203 -1 -0.01563 0.97266 0.01172 0.93359 -0.01953 -1 0.16406 -1 -0.00391 0.95313 -0.03516 0.92188 -0.02734 -0.99219 0.11719 -0.93359 0.34766 0.95703 -0.00391 0.82041 0.13758 0.90234 -0.06641 -1 -0.18750 -1 -0.34375 b +1 0 0.95202 0.02254 0.93757 -0.01272 0.93526 0.01214 0.96705 -0.01734 0.96936 0.00520 0.95665 -0.03064 0.95260 -0.00405 0.99480 -0.02659 0.99769 0.01792 0.93584 -0.04971 0.93815 -0.02370 0.97052 -0.04451 0.96215 -0.01647 0.97399 0.01908 0.95434 -0.03410 0.95838 0.00809 g +1 0 1 -0.05529 1 -1 0.5 -0.11111 0.36111 -0.22222 1 -0.25712 0.16667 -0.11111 1 -0.34660 1 -0.38853 1 -0.42862 0 -0.25000 1 -0.50333 1 -0.27778 1 -0.57092 1 -0.27778 1 -0.63156 1 -0.65935 b +1 0 0.31034 -0.10345 0.24138 -0.10345 0.20690 -0.06897 0.07405 -0.05431 0.03649 -0.03689 0.01707 -0.02383 0.00741 -0.01482 0.00281 -0.00893 0.00078 -0.00523 -0.00003 -0.00299 -0.00028 -0.00166 -0.00031 -0.00090 -0.00025 -0.00048 -0.00018 -0.00024 -0.00012 -0.00012 -0.00008 -0.00006 g +1 0 0.62745 -0.07843 0.72549 0 0.60784 -0.07843 0.62745 -0.11765 0.68627 -0.11765 0.66667 -0.13725 0.64706 -0.09804 0.54902 -0.11765 0.54902 -0.21569 0.58824 -0.19608 0.66667 -0.23529 0.45098 -0.25490 0.52409 -0.24668 0.56863 -0.31373 0.43137 -0.21569 0.47059 -0.27451 b +1 0 0.25000 0.16667 0.46667 0.26667 0.19036 0.23966 0.07766 0.19939 0.01070 0.14922 -0.02367 0.10188 -0.03685 0.06317 -0.03766 0.03458 -0.03230 0.01532 -0.02474 0.00357 -0.01726 -0.00273 -0.01097 -0.00539 -0.00621 -0.00586 -0.00294 -0.00520 -0.00089 -0.00408 0.00025 -0.00291 g +1 0 -0.65625 0.15625 0.06250 0 0 0.06250 0.62500 0.06250 0.18750 0 -0.03125 0.09375 0.06250 0 0.15625 -0.15625 0.43750 -0.37500 0 -0.09375 0 0 0.03125 -0.46875 0.03125 0 -0.71875 0.03125 -0.03125 0 0 0.09375 b +1 0 1 -0.01081 1 -0.02703 1 -0.06486 0.95135 -0.01622 0.98919 -0.03243 0.98919 0.08649 1 -0.06486 0.95135 0.09189 0.97838 -0.00541 1 0.06486 1 0.04324 0.97838 0.09189 0.98556 0.01251 1 -0.03243 1 0.02703 1 -0.07027 g +1 0 0.85271 0.05426 1 0.08069 1 1 0.91473 -0.00775 0.83721 0.03876 1 0.27153 1 1 0.81395 0.04651 0.90698 0.11628 1 0.50670 1 -1 0.80620 0.03876 1 0.71613 0.84496 0.06977 1 0.87317 1 1 b +1 0 0.90374 -0.01604 1 0.08021 1 0.01604 0.93048 0.00535 0.93583 -0.01604 1 0 1 0.06417 1 0.04813 0.91444 0.04278 0.96791 0.02139 0.98930 -0.01604 0.96257 0.05348 0.96974 0.04452 0.87701 0.01070 1 0.09091 0.97861 0.06417 g +1 0 -0.20500 0.28750 0.23000 0.10000 0.28250 0.31750 0.32250 0.35000 0.36285 -0.34617 0.09250 0.27500 -0.09500 0.21000 -0.08750 0.23500 -0.34187 0.31408 -0.48000 -0.08000 0.29908 0.33176 -0.58000 -0.24000 0.32190 -0.28475 -0.47000 0.18500 -0.27104 -0.31228 0.40445 0.03050 b +1 0 0.60000 0.03333 0.63333 0.06667 0.70000 0.06667 0.70000 0 0.63333 0 0.80000 0 0.73333 0 0.70000 0.10000 0.66667 0.10000 0.73333 -0.03333 0.76667 0 0.63333 0.13333 0.65932 0.10168 0.60000 0.13333 0.60000 0.16667 0.63333 0.16667 g +1 0 0.05866 -0.00838 0.06704 0.00838 0 -0.01117 0.00559 -0.03911 0.01676 -0.07542 -0.00559 0.05307 0.06425 -0.03352 0 0.09497 -0.06425 0.07542 -0.04749 0.02514 0.02793 -0.00559 0.00838 0.00559 0.10335 -0.00838 0.03073 -0.00279 0.04469 0 0.04749 -0.03352 b +1 0 0.94653 0.28713 0.72554 0.67248 0.47564 0.82455 0.01267 0.89109 -0.24871 0.84475 -0.47644 0.56079 -0.75881 0.41743 -0.66455 0.07208 -0.65426 -0.19525 -0.52475 -0.44000 -0.30851 -0.55089 -0.04119 -0.64792 0.16085 -0.56420 0.36752 -0.41901 0.46059 -0.22535 0.50376 -0.05980 g +1 0 0.05460 0.01437 -0.02586 0.04598 0.01437 0.04598 -0.07759 0.00862 0.01724 -0.06609 -0.03736 0.04310 -0.08333 -0.04598 -0.09483 0.08046 -0.04023 0.05172 0.02011 0.02299 -0.03736 -0.01149 0.03161 -0.00862 0.00862 0.01724 0.02586 0.01149 0.02586 0.01149 -0.04598 -0.00575 b +1 0 0.72414 -0.01084 0.79704 0.01084 0.80000 0.00197 0.79015 0.01084 0.78424 -0.00985 0.83350 0.03251 0.85123 0.01675 0.80099 -0.00788 0.79113 -0.02956 0.75961 0.03350 0.74778 0.05517 0.72611 -0.01478 0.78041 0.00612 0.74089 -0.05025 0.82956 0.02956 0.79015 0.00788 g +1 0 0.03852 0.02568 0.00428 0 0.01997 -0.01997 0.02140 -0.04993 -0.04850 -0.01284 0.01427 -0.02282 0 -0.03281 -0.04708 -0.02853 -0.01712 0.03566 0.02140 0.00428 0.05136 -0.02282 0.05136 0.01854 0.03994 0.01569 0.01997 0.00713 -0.02568 -0.01854 -0.01427 0.01997 b +1 0 0.47090 0.22751 0.42328 0.33598 0.25661 0.47619 0.01852 0.49471 -0.02116 0.53968 -0.34127 0.31217 -0.41270 0.32540 -0.51587 0.06878 -0.5 -0.11640 -0.14815 -0.14550 -0.14815 -0.38095 -0.23280 0.00265 0.03574 -0.31739 0.15873 -0.21693 0.24868 -0.24339 0.26720 0.04233 g +1 0 0.08696 0.00686 0.13959 -0.04119 0.10526 -0.08238 0.12586 -0.06178 0.23341 -0.01144 0.12357 0.07780 0.14645 -0.13501 0.29062 -0.04805 0.18993 0.07323 0.11670 0 0.11213 -0.00229 0.15103 -0.10297 0.08467 0.01373 0.11213 -0.06636 0.09611 -0.07323 0.11670 -0.06865 b +1 0 0.94333 0.38574 0.48263 0.64534 0.21572 0.77514 -0.55941 0.64899 -0.73675 0.42048 -0.76051 0 -0.62706 -0.31079 -0.38391 -0.62157 -0.12797 -0.69287 0.49909 -0.63620 0.71481 -0.37660 0.73857 -0.05484 0.60098 0.30384 0.45521 0.60512 0.02742 0.54479 -0.21572 0.50457 g +1 0 0.01975 0.00705 0.04090 -0.00846 0.02116 0.01128 0.01128 0.04372 0.00282 0.00141 0.01975 -0.03103 -0.01975 0.06065 -0.04090 0.02680 -0.02398 -0.00423 0.04372 -0.02539 0.01834 0 0 -0.01269 0.01834 -0.01128 0.00564 -0.01551 -0.01693 -0.02398 0.00705 0 b +1 0 0.85736 0.00075 0.81927 -0.05676 0.77521 -0.04182 0.84317 0.09037 0.86258 0.11949 0.88051 -0.06124 0.78342 0.03510 0.83719 -0.06796 0.83570 -0.14190 0.88125 0.01195 0.90515 0.02240 0.79686 -0.01942 0.82383 -0.03678 0.88125 -0.06423 0.73936 -0.01942 0.79089 -0.09186 g +1 0 1 -1 1 1 -1 1 1 -1 1 -1 -1 -1 -1 1 1 1 1 1 -1 1 1 -1 1 -1 1 1 1 1 -1 1 -1 1 b +1 0 0.85209 0.39252 0.38887 0.76432 0.08858 0.98903 -0.42625 0.88744 -0.76229 0.49980 -0.93092 0.10768 -0.85900 -0.31044 -0.66030 -0.55262 -0.19260 -0.86063 0.28444 -0.80496 0.64649 -0.35230 0.77814 -0.23324 0.71698 0.21343 0.37830 0.58310 0.19667 0.66315 -0.11215 0.64933 g +1 0 1 1 1 0.51250 0.62500 -1 1 1 0.02500 0.03125 1 1 0 0 1 -1 1 1 1 1 0.31250 1 1 1 1 1 1 1 -0.94375 1 0 0 b +1 0 1 0.54902 0.62745 1 0.01961 1 -0.49020 0.92157 -0.82353 0.58824 -1 0.11765 -0.96078 -0.33333 -0.64706 -0.68627 -0.23529 -0.86275 0.35294 -1 0.74510 -0.72549 0.92157 -0.21569 0.92874 0.21876 0.72549 0.56863 0.23529 0.90196 -0.11765 0.90196 g +1 0 0 0 -1 -1 -1 1 0 0 -1 1 1 1 1 -1 0 0 0 0 -1 -1 -1 1 1 0.43750 1 -1 0 0 -1 -1 -1 1 b +1 0 0.44444 0.44444 0.53695 0.90763 -0.22222 1 -0.33333 0.88889 -1 0.33333 -1 -0.11111 -1 -0.22222 -0.66667 -0.77778 0.55556 -1 -0.22222 -0.77778 0.77778 -0.22222 0.33333 0 0.92120 0.45019 0.57454 0.84353 0.22222 1 -0.55556 1 g +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 b +1 0 1 0 1 0 0.5 0.50000 0.75000 0 0.91201 0.12094 0.89067 0.14210 0.86922 0.16228 0.75000 0.25000 0.75000 0.5 0.75000 0 1 -0.25000 0.5 0.50000 0.73944 0.26388 0.75000 0.25000 0.69635 0.29074 0.67493 0.30293 g +0 0 -1 1 1 1 0 0 1 -1 1 -1 1 -1 -1 -1 0 0 -1 -1 0 0 0 0 -1 -1 1 -1 1 1 -1 -1 0 0 b +1 0 1 0 1 0 0.66667 0.11111 1 -0.11111 0.88889 -0.11111 1 -0.22222 0.77778 0 0.77778 0 1 -0.11111 0.77778 -0.11111 0.66667 -0.11111 0.66667 0 0.90347 -0.05352 1 0.11111 0.88889 -0.11111 1 0 g +0 0 0 0 0 0 0 0 0 0 0 0 -1 -1 0 0 1 0.75000 0 0 0 0 -1 1 0 0 1 -1 -1 -1 1 1 0 0 b +1 0 1 0.45455 1 -0.45455 1 0.09091 1 -0.09091 1 0 1 -0.27273 1 -0.18182 1 0.09091 1 0 1 -0.36364 1 0.09091 1 -0.09091 1 -0.04914 1 0.45455 1 -0.27273 1 -0.18182 g +1 0 0.62121 -0.63636 0 0 0 0 0.34470 0.28788 0.42803 0.39394 -0.07576 0.51894 0.36364 0.31439 -0.53788 0.32955 0.12121 -0.14773 0.01894 -0.53409 -0.57576 0.17803 0.29167 -0.27273 0.25758 -0.57576 0.43182 0.24242 0.18182 -0.02273 0.17045 -0.41667 b +1 0 1 0.11765 1 0.23529 1 0.41176 1 0.05882 1 0.23529 1 0.11765 1 0.47059 1 -0.05882 1 -0.11765 1 0.35294 1 0.41176 1 -0.11765 1 0.20225 1 0.05882 1 0.35294 1 0.23529 g +1 0 0 0 -1 -0.62766 1 0.51064 0.07979 -0.23404 -1 -0.36170 0.12766 -0.59043 1 -1 0 0 0.82979 -0.07979 -0.25000 1 0.17021 -0.70745 0 0 -0.19149 -0.46809 -0.22340 -0.48936 0.74468 0.90426 -0.67553 0.45745 b +1 0 0.91667 0.29167 0.83333 -0.16667 0.70833 0.25000 0.87500 -0.08333 0.91667 0.04167 0.83333 0.12500 0.70833 0 0.87500 0.04167 1 0.08333 0.66667 -0.08333 0.75000 0.16667 0.83333 -0.12500 0.83796 0.05503 1 0.20833 0.70833 0 0.70833 0.04167 g +1 0 0.18590 -0.16667 0 0 0 0 0 0 0 0 0.11538 -0.19071 0 0 0 0 0 0 0 0 -0.05128 -0.06571 0.07853 0.08974 0.17308 -0.10897 0.12500 0.09615 0.02564 -0.04808 0.16827 0.19551 b +1 0 1 -0.08183 1 -0.11326 0.99246 -0.29802 1 -0.33075 0.96662 -0.34281 0.85788 -0.47265 0.91904 -0.48170 0.73084 -0.65224 0.68131 -0.63544 0.82450 -0.78316 0.58829 -0.74785 0.67033 -0.96296 0.48757 -0.85669 0.37941 -0.83893 0.24117 -0.88846 0.29221 -0.89621 g +1 0 1 1 -1 1 -1 -0.82456 0.34649 0.21053 0.46053 0.07018 0.22807 0.05702 0.35088 0.34649 0.72807 -0.03947 0.22807 0.53070 0 0 -0.29825 -0.16228 1 -0.66667 1 -1 1 -0.24561 0.35088 0.20175 0.82895 0.07895 b +1 0 1 0.24077 0.99815 0.00369 0.80244 -0.30133 0.89919 -0.23486 0.70643 -0.24077 0.73855 -0.30539 0.71492 -0.36078 0.47194 -0.61189 0.40473 -0.55059 0.61041 -0.39328 0.53176 -0.32681 0.23966 -0.52142 0.29208 -0.48390 0.12777 -0.39143 0.15657 -0.51329 0.18353 -0.46603 g +0 0 -1 1 1 -1 0 0 0 0 1 -1 1 1 0 0 1 -1 0 0 0 0 1 1 -1 1 1 -1 -1 1 -1 -1 0 0 b +1 0 0.92247 -0.19448 0.96419 -0.17674 0.87024 -0.22602 0.81702 -0.27070 0.79271 -0.28909 0.70302 -0.49639 0.63338 -0.49967 0.37254 -0.70729 0.27070 -0.72109 0.40506 -0.54172 0.33509 -0.59691 0.14750 -0.63601 0.09312 -0.59589 -0.07162 -0.54928 -0.01840 -0.54074 -0.07457 -0.47898 g +1 0 -1 -1 -0.50694 1 1 -1 1 0.53819 0 0 0.23958 -1 1 1 0 0 1 1 1 1 0 0 -0.71528 1 0.33333 -1 1 -1 0.69792 -1 0.47569 1 b +1 0 0.84177 0.43460 0.5 0.76160 0.09916 0.93460 -0.37764 0.88186 -0.72363 0.61181 -0.93882 0.19409 -0.86709 -0.25527 -0.62869 -0.65612 -0.25105 -0.85654 0.16245 -0.86498 0.51477 -0.66878 0.74895 -0.28903 0.77937 0.07933 0.64135 0.42827 0.31435 0.62447 -0.00422 0.69409 g +1 0 1 1 0 0 1 -1 -1 -1 1 1 1 -1 0 0 1 -1 1 1 0 0 1 -1 -1 -1 1 1 -1 1 -1 1 0 0 b +1 0 1 0.63548 1 1 0.77123 1 -0.33333 1 -1 1 0 1 -1 1 -1 0 -1 -0.66667 -1 -0.92536 -1 -0.33333 -0.33333 -1 0.19235 -1 1 -1 0 -1 1 -0.66667 g +0 0 -1 1 -1 -1 0 0 -1 1 1 -1 -1 -1 -1 1 0 0 -1 -1 -1 1 0 0 1 -1 1 1 1 -1 1 1 0 0 b +1 0 1 0.06843 1 0.14211 1 0.22108 1 -0.12500 1 0.39495 1 0.48981 1 0.58986 -0.37500 1 1 0 1 0.92001 1 1 1 1 1 1 1 0.25000 1 1 1 1 g +0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 -1 -1 0 0 1 1 1 -1 1 -1 0 0 0 0 0 0 b +1 0 0.64947 -0.07896 0.58264 -0.14380 -0.13129 -0.21384 0.29796 0.04403 0.38096 -0.26339 0.28931 -0.31997 0.03459 -0.18947 0.20269 -0.29441 0.15196 -0.29052 0.09513 -0.31525 0.06556 -0.26795 0.03004 -0.25124 -0.00046 -0.23210 -0.02612 -0.21129 -0.04717 -0.18950 0.01336 -0.27201 g +1 0 0 0 0 0 0 0 0 0 1 -0.33333 0.16667 0.26042 0 0 0 0 0 0 -0.19792 -0.21875 -0.16667 0.90625 -1 0.5 0.04167 0.75000 -0.22917 -1 -0.12500 -0.27083 -0.19792 -0.93750 b +1 0 1 0.05149 0.99363 0.10123 0.96142 0.14756 0.95513 -0.26496 0.66026 0.54701 0.80426 0.25283 0.73781 0.27380 0.66775 0.28714 0.59615 0.29304 0.52494 0.29200 0.45582 0.28476 0.39023 0.27226 0.32930 0.25553 0.27381 0.23568 0.22427 0.21378 0.18086 0.19083 g +1 0 1 -0.09524 -1 -1 -1 -1 1 0.31746 0.81349 0.76190 -1 -1 -1 1 0.47364 1 1 1 0.68839 -1 -1 -1 0.82937 0.36508 1 1 1 0.50794 -1 -0.32540 -1 0.72831 b +1 0 0.93669 -0.00190 0.60761 0.43204 0.92314 -0.40129 0.93123 0.16828 0.96197 0.09061 0.99676 0.08172 0.91586 0.05097 0.84628 -0.25324 0.87379 -0.14482 0.84871 0.26133 0.75081 -0.03641 0.84547 -0.02589 0.87293 -0.02302 0.98544 0.09385 0.78317 -0.10194 0.85841 -0.14725 g +1 0 1 -1 1 1 1 1 1 -0.5 1 1 1 1 1 1 0 0 1 1 1 1 1 -1 1 1 1 0.62500 1 -0.75000 -0.75000 1 1 1 b +1 0 1 0.23058 1 -0.78509 1 -0.10401 1 0.15414 1 0.27820 0.98120 -0.06861 1 0.06610 0.95802 -0.18954 0.83584 -0.15633 0.97400 0.03728 0.99624 0.09242 1 -0.01253 0.96238 -0.04597 0.91165 0.03885 1 -0.13722 0.96523 -0.11717 g +1 0 0.36876 -1 -1 -1 -0.07661 1 1 0.95041 0.74597 -0.38710 -1 -0.79313 -0.09677 1 0.48684 0.46502 0.31755 -0.27461 -0.14343 -0.20188 -0.11976 0.06895 0.03021 0.06639 0.03443 -0.01186 -0.00403 -0.01672 -0.00761 0.00108 0.00015 0.00325 b +1 0 0.79847 0.38265 0.80804 -0.16964 1 -0.07653 0.98151 -0.07398 0.70217 0.20663 0.99745 0.02105 0.98214 0.02487 1 -0.13074 0.95663 0.07717 1 0.00191 0.90306 0.30804 1 -0.14541 1 -0.00394 0.75638 0.07908 1 -0.18750 1 -0.05740 g +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 -1 0 0 1 1 1 -1 1 1 1 0 1 1 1 -1 0 0 b +1 0 1 -0.28428 1 -0.25346 0.94623 -0.35094 1 -0.30566 0.92736 -0.49057 0.90818 -0.44119 0.75723 -0.58899 0.69748 -0.58019 0.59623 -0.57579 0.68459 -0.70975 0.54465 -0.87327 0.49214 -0.73333 0.35504 -0.76054 0.26352 -0.78239 0.16604 -0.73145 0.13994 -0.70000 g +1 0 0 0 0 0 0 0 -0.85000 -1 0 0 1 -1 0 0 -1 -1 -1 -1 1 -1 -0.60000 -1 1 1 -1 -0.20000 1 -1 0 1 0 0 b +1 0 1 0.09091 0.95455 -0.09091 0.77273 0 1 0 0.95455 0 1 0.04545 0.90909 -0.04545 1 0 1 0 0.86364 0.09091 0.77273 0.09091 0.90909 0.04545 0.91541 0.02897 0.95455 0.09091 0.86364 -0.09091 0.86364 0.04545 g +0 0 0 0 -1 1 1 1 -1 -1 0 0 -1 -1 -1 -0.31250 -1 -1 1 -1 1 -1 0 0 1 -1 -1 -1 0 0 1 -1 0 0 b +1 0 0.91176 -0.08824 0.97059 0.17647 0.82353 0.08824 0.91176 -0.02941 0.97059 -0.17647 0.97059 0.14706 0.94118 0.02941 1 0 1 0 0.76471 0.11765 0.88235 0.02941 0.85294 0.02941 0.92663 0.02600 0.94118 -0.11765 0.97059 0.05882 0.91176 0.05882 g +1 0 -1 1 -1 0.15244 0.28354 1 -1 1 -1 -1 1 1 -1 -0.23476 0.28301 -1 1 1 -0.31402 -1 -1 -1 1 -1 -1 -0.03578 1 -1 -1 -0.32317 0.14939 1 b +1 0 0.47368 -0.10526 0.83781 0.01756 0.83155 0.02615 0.68421 -0.05263 0.68421 0 0.79856 0.05028 0.78315 0.05756 0.84211 0.47368 1 0.05263 0.72550 0.07631 0.70301 0.08141 0.42105 0.21053 0.65419 0.08968 0.52632 -0.21053 0.60150 0.09534 0.57418 0.09719 g +1 0 -0.00641 -0.5 0 0 -0.01923 1 0 0 0 0 0 0 0 0 0 0 0.31410 0.92949 -0.35256 0.74359 -0.34615 -0.80769 0 0 -0.61538 -0.51282 0 0 0 0 0 0 b +1 0 1 0.45455 1 0.54545 0.81818 0.63636 1 -0.09091 1 0 0.81818 -0.45455 0.63636 0.27273 1 -0.63636 1 -0.27273 0.90909 -0.45455 1 0.07750 1 -0.09091 1 0.08867 1 0.36364 1 0.63636 0.72727 0.27273 g +0 0 -1 -1 1 -1 -1 1 0 0 1 -1 1 -1 0 0 0 0 0 0 -1 1 1 -1 -1 1 1 1 0 0 1 0.5 0 0 b +1 0 0.45455 0.09091 0.63636 0.09091 0.27273 0.18182 0.63636 0 0.36364 -0.09091 0.45455 -0.09091 0.48612 -0.01343 0.63636 -0.18182 0.45455 0 0.36364 -0.09091 0.27273 0.18182 0.36364 -0.09091 0.34442 -0.01768 0.27273 0 0.36364 0 0.28985 -0.01832 g +1 0 -1 -0.59677 0 0 -1 0.64516 -0.87097 1 0 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0.29839 0.23387 1 0.51613 0 0 0 0 0 0 b +1 0 1 0.14286 1 0.71429 1 0.71429 1 -0.14286 0.85714 -0.14286 1 0.02534 1 0 0.42857 -0.14286 1 0.03617 1 -0.28571 1 0 0.28571 -0.28571 1 0.04891 1 0.05182 1 0.57143 1 0 g +0 0 1 1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 -1 1 -1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 b +1 0 0.87032 0.46972 0.53945 0.82161 0.10380 0.95275 -0.38033 0.87916 -0.73939 0.58226 -0.92099 0.16731 -0.82417 -0.24942 -0.59383 -0.63342 -0.24012 -0.82881 0.18823 -0.78699 0.51557 -0.57430 0.69274 -0.24843 0.69097 0.10484 0.52798 0.39762 0.25974 0.56573 -0.06739 0.57552 g +0 0 1 -1 1 1 1 -1 1 1 1 -1 1 -1 1 -1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 -1 b +1 0 0.92657 0.04174 0.89266 0.15766 0.86098 0.19791 0.83675 0.36526 0.80619 0.40198 0.76221 0.40552 0.66586 0.48360 0.60101 0.51752 0.53392 0.52180 0.48435 0.54212 0.42546 0.55684 0.33340 0.55274 0.26978 0.54214 0.22307 0.53448 0.14312 0.49124 0.11573 0.46571 g +0 0 1 1 1 -1 1 -1 1 1 0 0 1 -1 0 0 0 0 0 0 -1 1 1 1 0 0 1 1 0 0 -1 -1 0 0 b +1 0 0.93537 0.13645 0.93716 0.25359 0.85705 0.38779 0.79039 0.47127 0.72352 0.59942 0.65260 0.75000 0.50830 0.73586 0.41629 0.82742 0.25539 0.85952 0.13712 0.85615 0.00494 0.88869 -0.07361 0.79780 -0.20995 0.78004 -0.33169 0.71454 -0.38532 0.64363 -0.47419 0.55835 g +0 0 1 -1 -1 1 -1 1 1 1 1 1 -1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 1 0 1 -1 1 -1 -1 1 -1 1 b +1 0 0.80627 0.13069 0.73061 0.24323 0.64615 0.19038 0.36923 0.45577 0.44793 0.46439 0.25000 0.57308 0.25192 0.37115 0.15215 0.51877 -0.09808 0.57500 -0.03462 0.42885 -0.08856 0.44424 -0.14943 0.40006 -0.19940 0.34976 -0.23832 0.29541 -0.26634 0.23896 -0.23846 0.31154 g +0 0 1 -1 1 1 1 -1 1 1 1 -1 1 1 1 -1 1 -1 1 1 1 1 1 -1 1 -1 1 -1 1 1 1 -1 1 1 b +1 0 0.97467 0.13082 0.94120 0.20036 0.88783 0.32248 0.89009 0.32711 0.85550 0.45217 0.72298 0.52284 0.69946 0.58820 0.58548 0.66893 0.48869 0.70398 0.44245 0.68159 0.35289 0.75622 0.26832 0.76210 0.16813 0.78541 0.07497 0.80439 -0.02962 0.77702 -0.10289 0.74242 g +0 0 0 0 1 1 0 0 1 1 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 -1 1 0 0 b +1 0 0.92308 0.15451 0.86399 0.29757 0.72582 0.36790 0.70588 0.56830 0.57449 0.62719 0.43270 0.74676 0.31705 0.67697 0.19128 0.76818 0.04686 0.76171 -0.12064 0.76969 -0.18479 0.71327 -0.29291 0.65708 -0.38798 0.58553 -0.46799 0.50131 -0.53146 0.40732 -0.56231 0.35095 g +0 0 0 0 1 1 1 1 0 0 0 0 -1 -1 0 0 -1 -1 0 0 0 0 1 1 0 0 1 1 0 0 -1 1 0 0 b +1 0 0.88804 0.38138 0.65926 0.69431 0.29148 0.87892 -0.06726 0.90135 -0.39597 0.80441 -0.64574 0.56502 -0.82960 0.26906 -0.78940 -0.08205 -0.62780 -0.30942 -0.46637 -0.55605 -0.16449 -0.64338 0.09562 -0.61055 0.30406 -0.48392 0.43227 -0.29838 0.47029 -0.09461 0.42152 0.12556 g +0 0 1 -1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 -1 1 -1 1 -1 1 -1 1 1 1 -1 1 1 1 1 b +1 0 0.73523 -0.38293 0.80151 0.10278 0.78826 0.15266 0.55580 0.05252 1 0.21225 0.71947 0.28954 0.68798 0.32925 0.49672 0.17287 0.64333 -0.02845 0.57399 0.42528 0.53120 0.44872 0.94530 0.57549 0.44174 0.48200 0.12473 1 0.35070 0.49721 0.30588 0.49831 g +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 b +1 0 0.94649 0.00892 0.97287 -0.00260 0.98922 0.00372 0.95801 0.01598 0.94054 0.03530 0.97213 0.04719 0.98625 0.01858 0.94277 0.07135 0.98551 -0.00706 0.97770 0.04980 0.96358 0.07098 0.93274 0.08101 0.95243 0.04356 0.97473 0.00818 0.97845 0.07061 1 -0.00260 g +0 0 1 1 -1 -1 -1 -1 0 0 0 0 -1 -1 0 0 0 0 0 0 -1 1 1 1 0 0 1 -1 0 0 -1 -1 -1 -1 b +1 0 0.50466 -0.16900 0.71442 0.01513 0.71063 0.02258 0.68065 0.01282 0.34615 0.05594 0.69050 0.04393 0.68101 0.05058 0.67023 0.05692 0.63403 -0.04662 0.64503 0.06856 0.63077 0.07381 0.84033 0.18065 0.59935 0.08304 0.38228 0.06760 0.56466 0.09046 0.54632 0.09346 g +1 0 0.68729 1 0.91973 -0.76087 0.81773 0.04348 0.76087 0.10702 0.86789 0.73746 0.70067 0.18227 0.75920 0.13712 0.93478 -0.25084 0.70736 0.18729 0.64883 0.24582 0.60201 0.77425 1 -0.53846 0.89262 0.22216 0.71070 0.53846 1 -0.06522 0.56522 0.23913 b +1 0 0.76296 -0.07778 1 -0.29630 1 -0.85741 0.80000 0.06111 0.45556 -0.42778 1 -0.12581 1 -0.83519 0.49259 0.01852 0.82222 -0.05926 0.98215 -0.19938 1 0.22037 0.69630 -0.26481 0.92148 -0.24549 0.78889 0.02037 0.87492 -0.27105 1 -0.57037 g +1 0 0.38521 0.15564 0.41245 0.07393 0.26459 0.24125 0.23346 0.13230 0.19455 0.25292 0.24514 0.36965 0.08949 0.22957 -0.03891 0.36965 0.05058 0.24903 0.24903 0.09728 0.07782 0.29961 -0.02494 0.28482 -0.06024 0.26256 -0.14786 0.14786 -0.09339 0.31128 -0.19066 0.28794 b +1 0 0.57540 -0.03175 0.75198 -0.05357 0.61508 -0.01190 0.53968 0.03373 0.61706 0.09921 0.59127 -0.02381 0.62698 0.01190 0.70833 0.02579 0.60317 0.01587 0.47817 -0.02778 0.59127 0.03770 0.5 0.03968 0.61291 -0.01237 0.61706 -0.13492 0.68849 -0.01389 0.62500 -0.03175 g +1 0 0.06404 -0.15271 -0.04433 0.05911 0.08374 -0.02463 -0.01478 0.18719 0.06404 0 0.12315 -0.09852 0.05911 0 0.01970 -0.02956 -0.12808 -0.20690 0.06897 0.01478 0.06897 0.02956 0.07882 0.16256 0.28079 -0.04926 -0.05911 -0.09360 0.04433 0.05419 0.07389 -0.10837 b +1 0 0.61857 0.10850 0.70694 -0.06935 0.70358 0.01678 0.74273 0.00224 0.71029 0.15772 0.71588 -0.00224 0.79754 0.06600 0.83669 -0.16555 0.68680 -0.09060 0.62528 -0.01342 0.60962 0.11745 0.71253 -0.09508 0.69845 -0.01673 0.63311 0.04810 0.78859 -0.05145 0.65213 -0.04698 g +1 0 0.25316 0.35949 0 0 -0.29620 -1 0 0 0.07595 -0.07342 0 0 0 0 0 0 0 0 0.00759 0.68101 -0.20000 0.33671 -0.10380 0.35696 0.05570 -1 0 0 0.06329 -1 0 0 b +1 0 0.88103 -0.00857 0.89818 -0.02465 0.94105 -0.01822 0.89175 -0.12755 0.82208 -0.10932 0.88853 0.01179 0.90782 -0.13719 0.87138 -0.06109 0.90782 -0.02358 0.87996 -0.14577 0.82851 -0.12433 0.90139 -0.19507 0.88245 -0.14903 0.84352 -0.12862 0.88424 -0.18542 0.91747 -0.16827 g +1 0 0.42708 -0.5 0 0 0 0 0.46458 0.51042 0.58958 0.02083 0 0 0 0 0.16458 -0.45417 0.59167 -0.18333 0 0 0 0 0.98750 -0.40833 -1 -1 -0.27917 -0.75625 0 0 0 0 b +1 0 0.88853 0.01631 0.92007 0.01305 0.92442 0.01359 0.89179 -0.10223 0.90103 -0.08428 0.93040 -0.01033 0.93094 -0.08918 0.86025 -0.05057 0.89451 -0.04024 0.88418 -0.12126 0.88907 -0.11909 0.82980 -0.14138 0.86453 -0.11808 0.85536 -0.13051 0.83524 -0.12452 0.86786 -0.12235 g +1 0 0 0 1 0.12889 0.88444 -0.02000 0 0 1 -0.42444 1 0.19556 1 -0.05333 1 -0.81556 0 0 1 -0.04000 1 -0.18667 0 0 1 -1 0 0 1 0.11778 0.90667 -0.09556 b +1 0 0.81143 0.03714 0.85143 -0.00143 0.79000 0.00714 0.79571 -0.04286 0.87571 0 0.85571 -0.06714 0.86429 0.00286 0.82857 -0.05429 0.81000 -0.11857 0.76857 -0.08429 0.84286 -0.05000 0.77000 -0.06857 0.81598 -0.08669 0.82571 -0.10429 0.81429 -0.05000 0.82143 -0.15143 g +1 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 0.55172 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 b +1 0 0.49870 0.01818 0.43117 -0.09610 0.50649 -0.04156 0.50130 0.09610 0.44675 0.05974 0.55844 -0.11948 0.51688 -0.03636 0.52727 -0.05974 0.55325 -0.01039 0.48571 -0.03377 0.49091 -0.01039 0.59221 0 0.53215 -0.03280 0.43117 0.03377 0.54545 -0.05455 0.58961 -0.08571 g +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 b +1 0 1 0.5 1 0.25000 0.25000 1 0.16851 0.91180 -0.13336 0.80454 -0.34107 0.60793 -0.43820 0.37856 -0.43663 0.16709 -0.36676 0.00678 -0.26477 -0.09025 -0.16178 -0.12964 -0.07782 -0.12744 -0.02089 -0.10242 0.01033 -0.07036 0.02224 -0.04142 0.02249 -0.02017 g +1 0 0 0 0 0 1 1 -1 -1 0 0 1 -0.11111 0 0 0 0 -1 1 1 1 1 -1 0 0 1 -1 0 0 0 0 1 1 b +1 0 0.87048 0.38027 0.64099 0.69212 0.31347 0.86625 -0.03933 0.90740 -0.42173 0.79346 -0.70561 0.51560 -0.81049 0.22735 -0.81136 -0.12539 -0.67474 -0.38102 -0.38334 -0.62861 -0.13013 -0.70762 0.15552 -0.66421 0.38544 -0.51568 0.52573 -0.29897 0.56239 -0.05938 0.51460 0.16645 g +1 0 0 0 0 0 0 0 -1 1 0 0 1 0.37333 -0.12000 -0.12000 0 0 -1 -1 0 0 1 -1 0 0 1 0.22667 0 0 0 0 0 0 b +1 0 0.88179 0.43491 0.59573 0.77655 0.19672 0.94537 -0.24103 0.92544 -0.62526 0.71257 -0.86443 0.33652 -0.92384 -0.05338 -0.77356 -0.44707 -0.46950 -0.73285 -0.10237 -0.82217 0.26384 -0.77570 0.55984 -0.55910 0.72147 -0.24433 0.72478 0.09599 0.58137 0.38915 0.34749 0.57656 g +1 0 0.32834 0.02520 0.15236 0.21278 0.14919 0.74003 -0.25706 0.92324 -0.10312 0.19380 -0.61352 0.25786 -0.94053 -0.05409 -0.13117 -0.14329 -0.30315 -0.44615 -0.11409 -0.85597 0.02668 -0.22786 0.27942 -0.06295 0.33737 -0.11876 0.27657 -0.11409 0.15078 0.13296 0.12197 0.20468 g +1 0 0.83427 0.39121 0.54040 0.78579 0.12326 0.89402 -0.33221 0.83578 -0.70086 0.59564 -0.86622 0.21909 -0.84442 -0.24164 -0.59714 -0.61894 -0.19354 -0.87787 0.12439 -0.89064 0.51109 -0.72454 0.79143 -0.27734 0.83008 0.08718 0.66592 0.49079 0.37542 0.70011 -0.03983 0.79444 g +1 0 0.62335 -0.03490 0.59085 0.00481 0.60409 -0.07461 0.63177 0.00963 0.62455 -0.07461 0.67028 0.07220 0.62936 -0.08424 0.67509 0.09146 0.67148 0 0.58965 0.10108 0.50060 0.03129 0.65945 0.14079 0.60463 0.02019 0.51384 0.04452 0.61733 -0.00963 0.61372 -0.09146 g +1 0 0.74449 -0.02390 0.70772 0.03309 0.72243 0.16912 0.79228 0.07721 0.81434 0.43934 0.63787 0.00551 0.70772 0.21691 1 0.06066 0.61029 0.05147 0.67463 0.04228 0.52022 -0.25000 0.72978 -0.15809 0.61727 0.07124 0.30882 0.08640 0.55916 0.07458 0.60294 0.21691 g +1 0 0.61538 0.18923 0.78157 0.01780 0.77486 0.02647 0.65077 -0.10308 0.77538 0.08000 0.73961 0.05060 0.72322 0.05776 0.68615 -0.08923 0.61692 0.16308 0.66233 0.07573 0.63878 0.08041 0.60154 -0.07231 0.58803 0.08767 0.55077 0.25692 0.53389 0.09207 0.50609 0.09322 g +1 0 0.68317 0.05375 0.84803 0.00202 0.84341 0.00301 0.84300 0.09901 0.75813 0.04102 0.81892 0.00585 0.80738 0.00673 0.80622 -0.12447 0.77935 -0.03536 0.76365 0.00909 0.74635 0.00978 0.79632 -0.04243 0.70824 0.01096 0.62235 0.11598 0.66624 0.01190 0.64407 0.01227 g +1 0 0.5 0 0.38696 0.10435 0.49130 0.06522 0.46957 -0.03913 0.35652 -0.12609 0.45652 0.04783 0.50435 0.02609 0.35652 0.19565 0.42174 0.14783 0.42174 -0.02609 0.32174 -0.11304 0.47391 -0.00870 0.41789 0.06908 0.38696 0.03913 0.35217 0.14783 0.44783 0.17391 g +1 0 0.79830 0.09417 0.78129 0.20656 0.71628 0.28068 0.69320 0.41252 0.65917 0.50122 0.57898 0.60814 0.49210 0.58445 0.33354 0.67861 0.29587 0.63548 0.09599 0.68104 0.02066 0.72236 -0.08748 0.63183 -0.11925 0.60696 -0.18226 0.56015 -0.25516 0.51701 -0.27339 0.42467 g +1 0 1 0.09802 1 0.25101 0.98390 0.33044 0.80365 0.53020 0.74977 0.60297 0.56937 0.71942 0.55311 0.74079 0.29452 0.82193 0.21137 0.79777 0.09709 0.82162 -0.01734 0.79870 -0.15144 0.75596 -0.22839 0.69187 -0.31713 0.60948 -0.40291 0.54522 -0.42815 0.44534 g +1 0 0.89410 0.13425 0.87001 0.31543 0.78896 0.43388 0.63388 0.59975 0.54003 0.71016 0.39699 0.76161 0.24266 0.79523 0.09134 0.79598 -0.09159 0.76261 -0.20201 0.66926 -0.30263 0.62610 -0.40552 0.50489 -0.46215 0.40753 -0.50314 0.27252 -0.52823 0.19172 -0.48808 0.05972 g +1 0 0.94631 0.17498 0.90946 0.33143 0.85096 0.49960 0.73678 0.63842 0.59215 0.73838 0.48698 0.83614 0.30459 0.90665 0.17959 0.93429 -0.00701 0.93109 -0.18880 0.89383 -0.33023 0.82492 -0.46534 0.76482 -0.58563 0.66335 -0.67929 0.52564 -0.75321 0.42488 -0.81210 0.26092 g +1 0 0.91767 0.18198 0.86090 0.35543 0.72873 0.45747 0.60425 0.69865 0.50376 0.74922 0.36100 0.81795 0.15664 0.83558 0.00396 0.85210 -0.16390 0.77853 -0.35996 0.76193 -0.43087 0.65385 -0.53140 0.53886 -0.60328 0.40972 -0.64511 0.27338 -0.65710 0.13667 -0.64056 0.05394 g +1 0 0.76627 0.21106 0.63935 0.38112 0.48409 0.52500 0.15000 0.22273 0.13753 0.59565 -0.07727 0.44545 0 0.48636 -0.27491 0.42014 -0.56136 0.36818 -0.36591 0.18864 -0.40533 0.07588 -0.38483 -0.03229 -0.33942 -0.12486 -0.27540 -0.19714 -0.19962 -0.24648 -0.11894 -0.27218 g +1 0 0.58940 -0.60927 0.85430 0.55298 0.81126 0.07285 0.56623 0.16225 0.32781 0.24172 0.50331 0.12252 0.63907 0.19868 0.71854 0.42715 0.54305 0.13907 0.65232 0.27815 0.68874 0.07285 0.51872 0.26653 0.49013 0.27687 0.46216 0.28574 0.43484 0.29324 0.40821 0.29942 g +1 0 1 0.11385 0.70019 -0.12144 0.81594 0.09677 0.71157 0.01139 0.56167 -0.07780 0.69070 0.12524 0.58634 0.03985 0.53131 -0.03416 0.69450 0.16888 0.72676 0.07211 0.32068 0.05882 0.53321 0.37381 0.49090 0.17951 0.15180 0.32448 0.44141 0.18897 0.56167 0.15180 g +1 0 0.84843 0.06794 0.80562 -0.02299 0.77031 -0.03299 0.66725 -0.06620 0.59582 -0.07666 0.67260 -0.05771 0.64260 -0.06438 0.39199 0.04530 0.71254 0.01394 0.55970 -0.08039 0.53430 -0.08453 0.47038 -0.22822 0.48659 -0.09128 0.52613 -0.08537 0.44277 -0.09621 0.42223 -0.09808 g +1 0 1 0.08013 0.96775 -0.00482 0.96683 -0.00722 0.87980 -0.03923 1 0.01419 0.96186 -0.01436 0.95947 -0.01671 0.98497 0.01002 0.91152 -0.08848 0.95016 -0.02364 0.94636 -0.02591 0.98164 0.02003 0.93772 -0.03034 1 -0.05843 0.92774 -0.03464 0.92226 -0.03673 g +1 0 0.47938 -0.12371 0.42784 -0.12371 0.70103 -0.39175 0.73196 0.07216 0.26289 -0.21649 0.49485 0.15979 0.45361 -0.11856 0.42268 0.06186 0.5 -0.27320 0.54639 0.18557 0.42268 0.08247 0.70619 0.19588 0.53396 -0.12447 0.15464 -0.26289 0.47423 0.04124 0.45361 -0.51546 g +1 0 0.63510 -0.04388 0.76530 0.02968 0.61432 0.36028 0.65358 -0.00462 0.64203 0.08314 0.79446 -0.43418 0.72517 0.54965 0.59584 0.13857 0.63510 0.21940 0.63279 -0.25404 0.70951 0.15359 0.64665 0.23095 0.68775 0.17704 0.61663 0.07621 0.66316 0.19841 0.69053 0.36721 g +1 0 0.50112 -0.03596 0.61124 0.01348 0.58876 0.01573 0.58876 0.02472 0.66742 -0.00449 0.71685 -0.04719 0.66517 0.00899 0.57303 0.02472 0.64719 -0.07416 0.56854 0.14157 0.57528 -0.03596 0.46517 0.04944 0.56588 0.00824 0.47640 -0.03596 0.54607 0.10562 0.60674 -0.08090 g +1 0 0.71521 -0.00647 0.66667 -0.04207 0.63107 -0.05178 0.77994 0.08091 0.67314 0.09709 0.64725 0.15858 0.60194 -0.01942 0.54369 -0.04531 0.46926 -0.10032 0.64725 0.14887 0.39159 0.21683 0.52427 -0.05502 0.45105 0.00040 0.31392 -0.06796 0.49191 -0.10680 0.30421 -0.05178 g +1 0 0.68148 0.10370 0.77037 0.03457 0.65185 0.08148 0.60988 -0.00494 0.79012 0.11852 0.59753 0.04938 0.62469 0.09630 0.78272 -0.17531 0.73827 -0.10864 0.48642 0.00988 0.60988 0.08148 0.66667 -0.12840 0.63773 -0.02451 0.76543 0.02222 0.61235 -0.07160 0.51358 -0.04691 g +1 0 0.60678 -0.02712 0.67119 0.04068 0.52881 -0.04407 0.50508 0.03729 0.70508 -0.07797 0.57966 -0.02034 0.53220 0.07797 0.64068 0.11864 0.56949 -0.02373 0.53220 0.00678 0.71525 -0.03390 0.52881 -0.03390 0.57262 0.00750 0.58644 -0.00339 0.58983 -0.02712 0.50169 0.06780 g +1 0 0.49515 0.09709 0.29612 0.05825 0.34951 0 0.57282 -0.02427 0.58252 0.02427 0.33495 0.04854 0.52427 0.00485 0.47087 -0.10680 0.43204 0.00485 0.34951 0.05825 0.18932 0.25728 0.31068 -0.15049 0.36547 0.03815 0.39320 0.17476 0.26214 0 0.37379 -0.01942 g +1 0 0.98822 0.02187 0.93102 0.34100 0.83904 0.35222 0.74706 0.48906 0.73584 0.51879 0.55076 0.60179 0.43130 0.66237 0.31800 0.70443 0.28379 0.68873 0.07515 0.73696 0.06338 0.71284 -0.16489 0.69714 -0.16556 0.60510 -0.16209 0.55805 -0.34717 0.44195 -0.33483 0.37465 g +1 0 0.97905 0.15810 0.90112 0.35237 0.82039 0.48561 0.71760 0.64888 0.58827 0.73743 0.40349 0.83156 0.25140 0.84804 0.04700 0.85475 -0.12193 0.79749 -0.26180 0.80754 -0.37835 0.71676 -0.51034 0.58324 -0.57587 0.46040 -0.61899 0.30796 -0.65754 0.18345 -0.64134 0.02968 g +1 0 0.99701 0.21677 0.91966 0.47030 0.76902 0.62415 0.53312 0.78120 0.36774 0.88291 0.10107 0.83312 -0.06827 0.89274 -0.28269 0.72073 -0.43707 0.61688 -0.55769 0.48120 -0.65000 0.35534 -0.64658 0.15908 -0.66651 0.02277 -0.64872 -0.13462 -0.54615 -0.22949 -0.47201 -0.35032 g +1 0 0.94331 0.19959 0.96132 0.40803 0.80514 0.56569 0.56687 0.70830 0.41836 0.83230 0.14939 0.89489 0.05167 0.93682 -0.24742 0.83939 -0.42811 0.75554 -0.50251 0.62563 -0.65515 0.50428 -0.68851 0.30912 -0.77097 0.15619 -0.75406 -0.04399 -0.75199 -0.17921 -0.66932 -0.34367 g +1 0 0.93972 0.28082 0.80486 0.52821 0.58167 0.73151 0.34961 0.80511 0.10797 0.90403 -0.20015 0.89335 -0.39730 0.82163 -0.58835 0.62867 -0.76305 0.40368 -0.81262 0.18888 -0.81317 -0.04284 -0.75273 -0.26883 -0.63237 -0.46438 -0.46422 -0.61446 -0.26389 -0.70835 -0.08937 -0.71273 g +1 0 0.89835 0.35157 0.67333 0.62233 0.43898 0.94353 -0.03643 0.80510 -0.22838 0.75334 -0.25137 0.48816 -0.57377 0.28415 -0.66750 0.10591 -0.47359 -0.06193 -0.81056 -0.06011 -0.33197 -0.47592 -0.12897 -0.53620 0.07158 -0.51925 0.24321 -0.43478 0.36586 -0.30057 0.42805 0.13297 g +1 0 0.29073 0.10025 0.23308 0.17293 0.03759 0.34336 0.12030 0.26316 0.06266 0.21303 -0.04725 0.12767 -0.06333 0.07907 -0.06328 0.04097 -0.05431 0.01408 -0.04166 -0.00280 -0.02876 -0.01176 -0.01755 -0.01505 -0.00886 -0.01475 -0.00280 -0.01250 0.00096 -0.00948 0.00290 -0.00647 g +1 0 0.58459 -0.35526 1 0.35338 0.75376 -0.00564 0.82519 0.19361 0.50188 -0.27632 0.65977 0.06391 0.69737 0.14662 0.72368 -0.42669 0.76128 0.04511 0.66917 0.20489 0.84774 -0.40977 0.64850 -0.04699 0.56836 -0.10571 0.52820 -0.13346 0.15602 -0.12218 0.44767 -0.10309 g +1 0 0.83609 0.13215 0.72171 0.06059 0.65829 0.08315 0.23888 0.12961 0.43837 0.20330 0.49418 0.12686 0.44747 0.13507 0.29352 0.02922 0.48158 0.15756 0.32835 0.14616 0.29495 0.14638 0.26436 0.14530 0.23641 0.14314 0.26429 0.16137 0.18767 0.13632 0.16655 0.13198 g +1 0 0.94080 0.11933 0.85738 0.01038 0.85124 0.01546 0.76966 -0.00278 0.84459 0.10916 0.83289 0.03027 0.82680 0.03506 0.74838 0.01943 0.80019 0.02405 0.80862 0.04901 0.80259 0.05352 0.77336 0.02220 0.79058 0.06235 0.85939 0.09251 0.77863 0.07090 0.77269 0.07508 g +1 0 0.87111 0.04326 0.79946 0.18297 0.99009 0.29292 0.89455 -0.08337 0.88598 -0.02028 0.90446 -0.26724 0.89410 0.19964 0.88644 -0.04642 0.84452 -0.00991 0.97882 -0.34024 0.78954 -0.25101 0.86661 -0.09193 0.85967 -0.02908 0.78774 -0.04101 0.75935 0.21812 0.88238 0.09193 g +1 0 0.74916 0.02549 0.98994 0.09792 0.75855 0.12877 0.74313 -0.09188 0.95842 0.02482 0.97921 -0.00469 0.96110 0.10195 0.91482 0.03756 0.71026 0.02683 0.81221 -0.08048 1 0 0.71764 -0.01207 0.82271 0.02552 0.72435 -0.01073 0.90409 0.11066 0.72837 0.02750 g +1 0 0.47337 0.19527 0.06213 -0.18343 0.62316 0.01006 0.45562 -0.04438 0.56509 0.01775 0.44675 0.27515 0.71598 -0.03846 0.55621 0.12426 0.41420 0.11538 0.52767 0.02842 0.51183 -0.10651 0.47929 -0.02367 0.46514 0.03259 0.53550 0.25148 0.31953 -0.14497 0.34615 -0.00296 g +1 0 0.59887 0.14689 0.69868 -0.13936 0.85122 -0.13936 0.80979 0.02448 0.50471 0.02825 0.67420 -0.04520 0.80791 -0.13748 0.51412 -0.24482 0.81544 -0.14313 0.70245 -0.00377 0.33333 0.06215 0.56121 -0.33145 0.61444 -0.16837 0.52731 -0.02072 0.53861 -0.31262 0.67420 -0.22034 g +1 0 0.84713 -0.03397 0.86412 -0.08493 0.81953 0 0.73673 -0.07643 0.71975 -0.13588 0.74947 -0.11677 0.77495 -0.18684 0.78132 -0.21231 0.61996 -0.10191 0.79193 -0.15711 0.89384 -0.03397 0.84926 -0.26115 0.74115 -0.23312 0.66242 -0.22293 0.72611 -0.37792 0.65817 -0.24841 g +1 0 0.87772 -0.08152 0.83424 0.07337 0.84783 0.04076 0.77174 -0.02174 0.77174 -0.05707 0.82337 -0.10598 0.67935 -0.00543 0.88043 -0.20924 0.83424 0.03261 0.86413 -0.05978 0.97283 -0.27989 0.85054 -0.18750 0.83705 -0.10211 0.85870 -0.03261 0.78533 -0.10870 0.79076 -0.00543 g +1 0 0.74704 -0.13241 0.53755 0.16996 0.72727 0.09486 0.69565 -0.11067 0.66798 -0.23518 0.87945 -0.19170 0.73715 0.04150 0.63043 -0.00395 0.63636 -0.11858 0.79249 -0.25296 0.66403 -0.28656 0.67194 -0.10474 0.61847 -0.12041 0.60079 -0.20949 0.37549 0.06917 0.61067 -0.01383 g +1 0 0.46785 0.11308 0.58980 0.00665 0.55432 0.06874 0.47894 -0.13969 0.52993 0.01330 0.63858 -0.16186 0.67849 -0.03326 0.54545 -0.13525 0.52993 -0.04656 0.47894 -0.19512 0.50776 -0.13525 0.41463 -0.20177 0.53930 -0.11455 0.59867 -0.02882 0.53659 -0.11752 0.56319 -0.04435 g +1 0 0.88116 0.27475 0.72125 0.42881 0.61559 0.63662 0.38825 0.90502 0.09831 0.96128 -0.20097 0.89200 -0.35737 0.77500 -0.65114 0.62210 -0.78768 0.45535 -0.81856 0.19095 -0.83943 -0.08079 -0.78334 -0.26356 -0.67557 -0.45511 -0.54732 -0.60858 -0.30512 -0.66700 -0.19312 -0.75597 g +1 0 0.93147 0.29282 0.79917 0.55756 0.59952 0.71596 0.26203 0.92651 0.04636 0.96748 -0.23237 0.95130 -0.55926 0.81018 -0.73329 0.62385 -0.90995 0.36200 -0.92254 0.06040 -0.93618 -0.19838 -0.83192 -0.46906 -0.65165 -0.69556 -0.41223 -0.85725 -0.13590 -0.93953 0.10007 -0.94823 g +1 0 0.88241 0.30634 0.73232 0.57816 0.34109 0.58527 0.05717 1 -0.09238 0.92118 -0.62403 0.71996 -0.69767 0.32558 -0.81422 0.41195 -1 -0.00775 -0.78973 -0.41085 -0.76901 -0.45478 -0.57242 -0.67605 -0.31610 -0.81876 -0.02979 -0.86841 0.25392 -0.82127 0.00194 -0.81686 g +1 0 0.83479 0.28993 0.69256 0.47702 0.49234 0.68381 0.21991 0.86761 -0.08096 0.85011 -0.35558 0.77681 -0.52735 0.58425 -0.70350 0.31291 -0.75821 0.03939 -0.71225 -0.15317 -0.58315 -0.39168 -0.37199 -0.52954 -0.16950 -0.60863 0.08425 -0.61488 0.25164 -0.48468 0.40591 -0.35339 g +1 0 0.92870 0.33164 0.76168 0.62349 0.49305 0.84266 0.21592 0.95193 -0.13956 0.96167 -0.47202 0.83590 -0.70747 0.65490 -0.87474 0.36750 -0.91814 0.05595 -0.89824 -0.26173 -0.73969 -0.54069 -0.50757 -0.74735 -0.22323 -0.86122 0.07810 -0.87159 0.36021 -0.78057 0.59407 -0.60270 g +1 0 0.83367 0.31456 0.65541 0.57671 0.34962 0.70677 0.17293 0.78947 -0.18976 0.79886 -0.41729 0.66541 -0.68421 0.47744 -0.74725 0.19492 -0.72180 -0.04887 -0.62030 -0.28195 -0.49165 -0.53463 -0.26577 -0.66014 -0.01530 -0.69706 0.22708 -0.64428 0.43100 -0.51206 0.64662 -0.30075 g +1 0 0.98455 -0.02736 0.98058 -0.04104 1 -0.07635 0.98720 0.01456 0.95278 -0.02604 0.98500 -0.07458 0.99382 -0.07149 0.97396 -0.09532 0.97264 -0.12224 0.99294 -0.05252 0.95278 -0.08914 0.97352 -0.08341 0.96653 -0.12912 0.93469 -0.14916 0.97132 -0.15755 0.96778 -0.18800 g +1 0 0.94052 -0.01531 0.94170 0.01001 0.94994 -0.01472 0.95878 -0.01060 0.94641 -0.03710 0.97173 -0.01767 0.97055 -0.03887 0.95465 -0.04064 0.95230 -0.04711 0.94229 -0.02179 0.92815 -0.04417 0.92049 -0.04476 0.92695 -0.05827 0.90342 -0.07479 0.91991 -0.07244 0.92049 -0.07420 g +1 0 0.97032 -0.14384 0.91324 -0.00228 0.96575 -0.17123 0.98630 0.18265 0.91781 0.00228 0.93607 -0.08447 0.91324 -0.00228 0.86758 -0.08676 0.97032 -0.21233 1 0.10274 0.92009 -0.05251 0.92466 0.06849 0.94043 -0.09252 0.97032 -0.20091 0.85388 -0.08676 0.96575 -0.21918 g +1 0 0.52542 -0.03390 0.94915 0.08475 0.52542 -0.16949 0.30508 -0.01695 0.50847 -0.13559 0.64407 0.28814 0.83051 -0.35593 0.54237 0.01695 0.55932 0.03390 0.59322 0.30508 0.86441 0.05085 0.40678 0.15254 0.67287 -0.00266 0.66102 -0.03390 0.83051 -0.15254 0.76271 -0.10169 g +1 0 0.33333 -0.25000 0.44444 0.22222 0.38889 0.16667 0.41667 0.13889 0.5 -0.11111 0.54911 -0.08443 0.58333 0.33333 0.55556 0.02778 0.25000 -0.19444 0.47222 -0.05556 0.52778 -0.02778 0.38889 0.08333 0.41543 -0.14256 0.19444 -0.13889 0.36924 -0.14809 0.08333 -0.5 g +1 0 0.51207 1 1 0.53810 0.71178 0.80833 0.45622 0.46427 0.33081 1 0.21249 1 -0.17416 1 -0.33081 0.98722 -0.61382 1 -0.52674 0.71699 -0.88500 0.47894 -1 0.35175 -1 0.09569 -1 -0.16713 -1 -0.42226 -0.91903 -0.65557 g +1 0 0.75564 0.49638 0.83550 0.54301 0.54916 0.72063 0.35225 0.70792 0.13469 0.94749 -0.09818 0.93778 -0.37604 0.82223 -0.52742 0.71161 -0.68358 0.67989 -0.70163 0.24956 -0.79147 0.02995 -0.98988 -0.29099 -0.70352 -0.32792 -0.63312 -0.19185 -0.34131 -0.60454 -0.19609 -0.62956 g +1 0 0.83789 0.42904 0.72113 0.58385 0.45625 0.78115 0.16470 0.82732 -0.13012 0.86947 -0.46177 0.78497 -0.59435 0.52070 -0.78470 0.26529 -0.84014 0.03928 -0.62041 -0.31351 -0.47412 -0.48905 -0.37298 -0.67796 -0.05054 -0.62691 0.14690 -0.45911 0.37093 -0.39167 0.48319 -0.24313 g +1 0 0.93658 0.35107 0.75254 0.65640 0.45571 0.88576 0.15323 0.95776 -0.21775 0.96301 -0.56535 0.83397 -0.78751 0.58045 -0.93104 0.26020 -0.93641 -0.06418 -0.87028 -0.40949 -0.65079 -0.67464 -0.36799 -0.84951 -0.04578 -0.91221 0.27330 -0.85762 0.54827 -0.69613 0.74828 -0.44173 g +1 0 0.92436 0.36924 0.71976 0.68420 0.29303 0.94078 -0.11108 0.76527 -0.31605 0.92453 -0.66616 0.78766 -0.92145 0.42314 -0.94315 0.09585 -1 0.03191 -0.66431 -0.66278 -0.46010 -0.78174 -0.13486 -0.88082 0.19765 -0.85137 0.48904 -0.70247 0.69886 -0.46048 0.76066 -0.13194 g +1 0 1 0.16195 1 -0.05558 1 0.01373 1 -0.12352 1 -0.01511 1 -0.01731 1 -0.06374 1 -0.07157 1 0.05900 1 -0.10108 1 -0.02685 1 -0.22978 1 -0.06823 1 0.08299 1 -0.14194 1 -0.07439 g +1 0 0.95559 -0.00155 0.86421 -0.13244 0.94982 -0.00461 0.82809 -0.51171 0.92441 0.10368 1 -0.14247 0.99264 -0.02542 0.95853 -0.15518 0.84013 0.61739 1 -0.16321 0.87492 -0.08495 0.85741 -0.01664 0.84132 -0.01769 0.82427 -0.01867 0.80634 -0.01957 0.78761 -0.02039 g +1 0 0.79378 0.29492 0.64064 0.52312 0.41319 0.68158 0.14177 0.83548 -0.16831 0.78772 -0.42911 0.72328 -0.57165 0.41471 -0.75436 0.16755 -0.69977 -0.09856 -0.57695 -0.23503 -0.40637 -0.38287 -0.17437 -0.52540 0.01523 -0.48707 0.19030 -0.38059 0.31008 -0.23199 0.34572 -0.08036 g +1 0 0.88085 0.35232 0.68389 0.65128 0.34816 0.79784 0.05832 0.90842 -0.29784 0.86490 -0.62635 0.69590 -0.77106 0.39309 -0.85803 0.08408 -0.81641 -0.24017 -0.64579 -0.50022 -0.39766 -0.68337 -0.11147 -0.75533 0.17041 -0.71504 0.40675 -0.57649 0.56626 -0.36765 0.62765 -0.13305 g +1 0 0.89589 0.39286 0.66129 0.71804 0.29521 0.90824 -0.04787 0.94415 -0.45725 0.84605 -0.77660 0.58511 -0.92819 0.25133 -0.92282 -0.15315 -0.76064 -0.48404 -0.50931 -0.76197 -0.14895 -0.88591 0.21581 -0.85703 0.53229 -0.68593 0.74846 -0.40656 0.83142 -0.07029 0.76862 0.27926 g +1 0 1 -0.24051 1 -0.20253 0.87342 -0.10127 0.88608 0.01266 1 0.11392 0.92405 0.06329 0.84810 -0.03797 0.63291 -0.36709 0.87342 -0.01266 0.93671 0.06329 1 0.25316 0.62025 -0.37975 0.84637 -0.05540 1 -0.06329 0.53165 0.02532 0.83544 -0.02532 g +1 0 0.74790 0.00840 0.83312 0.01659 0.82638 0.02469 0.86555 0.01681 0.60504 0.05882 0.79093 0.04731 0.77441 0.05407 0.64706 0.19328 0.84034 0.04202 0.71285 0.07122 0.68895 0.07577 0.66387 0.08403 0.63728 0.08296 0.61345 0.01681 0.58187 0.08757 0.55330 0.08891 g +1 0 0.85013 0.01809 0.92211 0.01456 0.92046 0.02180 0.92765 0.08010 0.87597 0.11370 0.91161 0.04320 0.90738 0.05018 0.87339 0.02842 0.95866 0 0.89097 0.07047 0.88430 0.07697 0.83721 0.10853 0.86923 0.08950 0.87597 0.08786 0.85198 0.10134 0.84258 0.10698 g +1 0 1 -0.01179 1 -0.00343 1 -0.01565 1 -0.01565 1 -0.02809 1 -0.02187 0.99828 -0.03087 0.99528 -0.03238 0.99314 -0.03452 1 -0.03881 1 -0.05039 1 -0.04931 0.99842 -0.05527 0.99400 -0.06304 0.99057 -0.06497 0.98971 -0.06668 g +1 0 0.89505 -0.03168 0.87525 0.05545 0.89505 0.01386 0.92871 0.02772 0.91287 -0.00990 0.94059 -0.01584 0.91881 0.03366 0.93663 0 0.94257 0.01386 0.90495 0.00792 0.88713 -0.01782 0.89307 0.02376 0.89002 0.01611 0.88119 0.00198 0.87327 0.04158 0.86733 0.02376 g +1 0 0.90071 0.01773 1 -0.01773 0.90071 0.00709 0.84752 0.05674 1 0.03546 0.97872 0.01064 0.97518 0.03546 1 -0.03191 0.89716 -0.03191 0.86170 0.07801 1 0.09220 0.90071 0.04610 0.94305 0.03247 0.94681 0.02482 1 0.01064 0.93617 0.02128 g +1 0 0.39394 -0.24242 0.62655 0.01270 0.45455 0.09091 0.63636 0.09091 0.21212 -0.21212 0.57576 0.15152 0.39394 0 0.56156 0.04561 0.51515 0.03030 0.78788 0.18182 0.30303 -0.15152 0.48526 0.05929 0.46362 0.06142 0.33333 -0.03030 0.41856 0.06410 0.39394 0.24242 g +1 0 0.86689 0.35950 0.72014 0.66667 0.37201 0.83049 0.08646 0.85893 -0.24118 0.86121 -0.51763 0.67577 -0.68714 0.41524 -0.77019 0.09898 -0.69397 -0.13652 -0.49488 -0.42207 -0.32537 -0.57679 -0.02844 -0.59954 0.15360 -0.53127 0.32309 -0.37088 0.46189 -0.19681 0.40956 0.01820 g +1 0 0.89563 0.37917 0.67311 0.69438 0.35916 0.88696 -0.04193 0.93345 -0.38875 0.84414 -0.67274 0.62078 -0.82680 0.30356 -0.86150 -0.05365 -0.73564 -0.34275 -0.51778 -0.62443 -0.23428 -0.73855 0.06911 -0.73856 0.33531 -0.62296 0.52414 -0.42086 0.61217 -0.17343 0.60073 0.08660 g +1 0 0.90547 0.41113 0.65354 0.74761 0.29921 0.95905 -0.13342 0.97820 -0.52236 0.83263 -0.79657 0.55086 -0.96631 0.15192 -0.93001 -0.25554 -0.71863 -0.59379 -0.41546 -0.85205 -0.02250 -0.93788 0.36318 -0.85368 0.67538 -0.61959 0.85977 -0.28123 0.88654 0.09800 0.75495 0.46301 g +1 0 1 1 0.36700 0.06158 0.12993 0.92713 -0.27586 0.93596 -0.31527 0.37685 -0.87192 0.36946 -0.92857 -0.08867 -0.38916 -0.34236 -0.46552 -0.82512 -0.05419 -0.93596 0.25616 -0.20443 0.73792 -0.45950 0.85471 -0.06831 1 1 0.38670 0.00246 0.17758 0.79790 g +1 0 1 0.51515 0.45455 0.33333 0.06061 0.36364 -0.32104 0.73062 -0.45455 0.48485 -0.57576 0 -0.57576 -0.12121 -0.33333 -0.48485 -0.09091 -0.84848 0.48485 -0.57576 0.57576 -0.42424 1 -0.39394 0.72961 0.12331 0.96970 0.57576 0.24242 0.36364 0.09091 0.33333 g +1 0 0.88110 0 0.94817 -0.02744 0.93598 -0.01220 0.90244 0.01829 0.90244 0.01829 0.93902 0.00915 0.95732 0.00305 1 0.02744 0.94207 -0.01220 0.90854 0.02439 0.91463 0.05488 0.99695 0.04878 0.89666 0.02226 0.90854 0.00915 1 0.05488 0.97561 -0.01220 g +1 0 0.82624 0.08156 0.79078 -0.08156 0.90426 -0.01773 0.92908 0.01064 0.80142 0.08865 0.94681 -0.00709 0.94326 0 0.93262 0.20213 0.95035 -0.00709 0.91489 0.00709 0.80496 0.07092 0.91135 0.15957 0.89527 0.08165 0.77660 0.06738 0.92553 0.18085 0.92553 0 g +1 0 0.74468 0.10638 0.88706 0.00982 0.88542 0.01471 0.87234 -0.01418 0.73050 0.10638 0.87657 0.02912 0.87235 0.03382 0.95745 0.07801 0.95035 0.04255 0.85597 0.04743 0.84931 0.05178 0.87234 0.11348 0.83429 0.06014 0.74468 -0.03546 0.81710 0.06800 0.80774 0.07173 g +1 0 0.87578 0.03727 0.89951 0.00343 0.89210 0.00510 0.86335 0 0.95031 0.07453 0.87021 0.00994 0.86303 0.01151 0.83851 -0.06211 0.85714 0.02484 0.84182 0.01603 0.83486 0.01749 0.79503 -0.04348 0.82111 0.02033 0.81988 0.08696 0.80757 0.02308 0.80088 0.02441 g +1 0 0.97513 0.00710 0.98579 0.01954 1 0.01954 0.99290 0.01599 0.95737 0.02309 0.97158 0.03552 1 0.03730 0.97869 0.02131 0.98579 0.05684 0.97158 0.04796 0.94494 0.05506 0.98401 0.03552 0.97540 0.06477 0.94849 0.08171 0.99112 0.06217 0.98934 0.09947 g +1 0 1 0.01105 1 0.01105 1 0.02320 0.99448 -0.01436 0.99448 -0.00221 0.98343 0.02320 1 0.00884 0.97569 0.00773 0.97901 0.01657 0.98011 0.00663 0.98122 0.02099 0.97127 -0.00663 0.98033 0.01600 0.97901 0.01547 0.98564 0.02099 0.98674 0.02762 g +1 0 1 -0.01342 1 0.01566 1 -0.00224 1 0.06264 0.97763 0.04474 0.95973 0.02908 1 0.06488 0.98881 0.03356 1 0.03579 0.99776 0.09396 0.95749 0.07383 1 0.10067 0.99989 0.08763 0.99105 0.08501 1 0.10067 1 0.10067 g +1 0 0.88420 0.36724 0.67123 0.67382 0.39613 0.86399 0.02424 0.93182 -0.35148 0.83713 -0.60316 0.58842 -0.78658 0.38778 -0.83285 -0.00642 -0.69318 -0.32963 -0.52504 -0.53924 -0.27377 -0.68126 0.00806 -0.69774 0.26028 -0.60678 0.44569 -0.43383 0.54209 -0.21542 0.56286 0.02823 g +1 0 0.90147 0.41786 0.64131 0.75725 0.30440 0.95148 -0.20449 0.96534 -0.55483 0.81191 -0.81857 0.50949 -0.96986 0.10345 -0.91456 -0.31412 -0.70163 -0.65461 -0.32354 -0.88999 0.05865 -0.94172 0.44483 -0.82154 0.74105 -0.55231 0.89415 -0.18725 0.87893 0.20359 0.70555 0.54852 g +1 0 0.32789 0.11042 0.15970 0.29308 0.14020 0.74485 -0.25131 0.91993 -0.16503 0.26664 -0.63714 0.24865 -0.97650 -0.00337 -0.23227 -0.19909 -0.30522 -0.48886 -0.14426 -0.89991 0.09345 -0.28916 0.28307 -0.18560 0.39599 -0.11498 0.31005 0.05614 0.21443 0.20540 0.13376 0.26422 g +1 0 0.65845 0.43617 0.44681 0.74804 0.05319 0.85106 -0.32027 0.82139 -0.68253 0.52408 -0.84211 0.07111 -0.82811 -0.28723 -0.47032 -0.71725 -0.04759 -0.86002 0.23292 -0.76316 0.56663 -0.52128 0.74300 -0.18645 0.74758 0.23713 0.45185 0.59071 0.20549 0.76764 -0.18533 0.74356 g +1 0 0.19466 0.05725 0.04198 0.25191 -0.10557 0.48866 -0.18321 -0.18321 -0.41985 0.06107 -0.45420 0.09160 -0.16412 -0.30534 -0.10305 -0.39695 0.18702 -0.17557 0.34012 -0.11953 0.28626 -0.16031 0.21645 0.24692 0.03913 0.31092 -0.03817 0.26336 -0.16794 0.16794 -0.30153 -0.33588 g +1 0 0.98002 0.00075 1 0 0.98982 -0.00075 0.94721 0.02394 0.97700 0.02130 0.97888 0.03073 0.99170 0.02338 0.93929 0.05713 0.93552 0.05279 0.97738 0.05524 1 0.06241 0.94155 0.08107 0.96709 0.07255 0.95701 0.08088 0.98190 0.08126 0.97247 0.08616 g +1 0 0.82254 -0.07572 0.80462 0.00231 0.87514 -0.01214 0.86821 -0.07514 0.72832 -0.11734 0.84624 0.05029 0.83121 -0.07399 0.74798 0.06705 0.78324 0.06358 0.86763 -0.02370 0.78844 -0.06012 0.74451 -0.02370 0.76717 -0.02731 0.74046 -0.07630 0.70058 -0.04220 0.78439 0.01214 g +1 0 0.35346 -0.13768 0.69387 -0.02423 0.68195 -0.03574 0.55717 -0.06119 0.61836 -0.10467 0.62099 -0.06527 0.59361 -0.07289 0.42271 -0.26409 0.58213 0.04992 0.49736 -0.08771 0.46241 -0.08989 0.45008 -0.00564 0.39146 -0.09038 0.35588 -0.10306 0.32232 -0.08637 0.28943 -0.08300 g +1 0 0.76046 0.01092 0.86335 0.00258 0.85821 0.00384 0.79988 0.02304 0.81504 0.12068 0.83096 0.00744 0.81815 0.00854 0.82777 -0.06974 0.76531 0.03881 0.76979 0.01148 0.75071 0.01232 0.77138 -0.00303 0.70886 0.01375 0.66161 0.00849 0.66298 0.01484 0.63887 0.01525 g +1 0 0.66667 -0.01366 0.97404 0.06831 0.49590 0.50137 0.75683 -0.00273 0.65164 -0.14071 0.40164 -0.48907 0.39208 0.58743 0.76776 0.31831 0.78552 0.11339 0.47541 -0.44945 1 0.00683 0.60656 0.06967 0.68656 0.17088 0.87568 0.07787 0.55328 0.24590 0.13934 0.48087 g +1 0 0.83508 0.08298 0.73739 -0.14706 0.84349 -0.05567 0.90441 -0.04622 0.89391 0.13130 0.81197 0.06723 0.79307 -0.08929 1 -0.02101 0.96639 0.06618 0.87605 0.01155 0.77521 0.06618 0.95378 -0.04202 0.83479 0.00123 1 0.12815 0.86660 -0.10714 0.90546 -0.04307 g +1 0 0.95113 0.00419 0.95183 -0.02723 0.93438 -0.01920 0.94590 0.01606 0.96510 0.03281 0.94171 0.07330 0.94625 -0.01326 0.97173 0.00140 0.94834 0.06038 0.92670 0.08412 0.93124 0.10087 0.94520 0.01361 0.93522 0.04925 0.93159 0.08168 0.94066 -0.00035 0.91483 0.04712 g +1 0 0.94701 -0.00034 0.93207 -0.03227 0.95177 -0.03431 0.95584 0.02446 0.94124 0.01766 0.92595 0.04688 0.93954 -0.01461 0.94837 0.02004 0.93784 0.01393 0.91406 0.07677 0.89470 0.06148 0.93988 0.03193 0.92489 0.02542 0.92120 0.02242 0.92459 0.00442 0.92697 -0.00577 g +1 0 0.90608 -0.01657 0.98122 -0.01989 0.95691 -0.03646 0.85746 0.00110 0.89724 -0.03315 0.89061 -0.01436 0.90608 -0.04530 0.91381 -0.00884 0.80773 -0.12928 0.88729 0.01215 0.92155 -0.02320 0.91050 -0.02099 0.89147 -0.07760 0.82983 -0.17238 0.96022 -0.03757 0.87403 -0.16243 g +1 0 0.84710 0.13533 0.73638 -0.06151 0.87873 0.08260 0.88928 -0.09139 0.78735 0.06678 0.80668 -0.00351 0.79262 -0.01054 0.85764 -0.04569 0.87170 -0.03515 0.81722 -0.09490 0.71002 0.04394 0.86467 -0.15114 0.81147 -0.04822 0.78207 -0.00703 0.75747 -0.06678 0.85764 -0.06151 g diff --git a/pyminer2/tests/datasets/iris_basket.basket b/pyminer2/tests/datasets/iris_basket.basket new file mode 100644 index 0000000000000000000000000000000000000000..302d36245cc4e4a5f9f6e76374b0f2d2dd657d3f --- /dev/null +++ b/pyminer2/tests/datasets/iris_basket.basket @@ -0,0 +1,150 @@ +"sepal_length"=5.1,"sepal_width"=3.5,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.9,"sepal_width"=3.0,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.7,"sepal_width"=3.2,"petal_length"=1.3,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.6,"sepal_width"=3.1,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.6,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.4,"sepal_width"=3.9,"petal_length"=1.7,"petal_width"=0.4|Iris-setosa +"sepal_length"=4.6,"sepal_width"=3.4,"petal_length"=1.4,"petal_width"=0.3|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.4,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.4,"sepal_width"=2.9,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.9,"sepal_width"=3.1,"petal_length"=1.5,"petal_width"=0.1|Iris-setosa +"sepal_length"=5.4,"sepal_width"=3.7,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.8,"sepal_width"=3.4,"petal_length"=1.6,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.8,"sepal_width"=3.0,"petal_length"=1.4,"petal_width"=0.1|Iris-setosa +"sepal_length"=4.3,"sepal_width"=3.0,"petal_length"=1.1,"petal_width"=0.1|Iris-setosa +"sepal_length"=5.8,"sepal_width"=4.0,"petal_length"=1.2,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.7,"sepal_width"=4.4,"petal_length"=1.5,"petal_width"=0.4|Iris-setosa +"sepal_length"=5.4,"sepal_width"=3.9,"petal_length"=1.3,"petal_width"=0.4|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.5,"petal_length"=1.4,"petal_width"=0.3|Iris-setosa +"sepal_length"=5.7,"sepal_width"=3.8,"petal_length"=1.7,"petal_width"=0.3|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.8,"petal_length"=1.5,"petal_width"=0.3|Iris-setosa +"sepal_length"=5.4,"sepal_width"=3.4,"petal_length"=1.7,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.7,"petal_length"=1.5,"petal_width"=0.4|Iris-setosa +"sepal_length"=4.6,"sepal_width"=3.6,"petal_length"=1.0,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.3,"petal_length"=1.7,"petal_width"=0.5|Iris-setosa +"sepal_length"=4.8,"sepal_width"=3.4,"petal_length"=1.9,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.0,"petal_length"=1.6,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.4,"petal_length"=1.6,"petal_width"=0.4|Iris-setosa +"sepal_length"=5.2,"sepal_width"=3.5,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.2,"sepal_width"=3.4,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.7,"sepal_width"=3.2,"petal_length"=1.6,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.8,"sepal_width"=3.1,"petal_length"=1.6,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.4,"sepal_width"=3.4,"petal_length"=1.5,"petal_width"=0.4|Iris-setosa +"sepal_length"=5.2,"sepal_width"=4.1,"petal_length"=1.5,"petal_width"=0.1|Iris-setosa +"sepal_length"=5.5,"sepal_width"=4.2,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.9,"sepal_width"=3.1,"petal_length"=1.5,"petal_width"=0.1|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.2,"petal_length"=1.2,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.5,"sepal_width"=3.5,"petal_length"=1.3,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.9,"sepal_width"=3.1,"petal_length"=1.5,"petal_width"=0.1|Iris-setosa +"sepal_length"=4.4,"sepal_width"=3.0,"petal_length"=1.3,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.4,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.5,"petal_length"=1.3,"petal_width"=0.3|Iris-setosa +"sepal_length"=4.5,"sepal_width"=2.3,"petal_length"=1.3,"petal_width"=0.3|Iris-setosa +"sepal_length"=4.4,"sepal_width"=3.2,"petal_length"=1.3,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.5,"petal_length"=1.6,"petal_width"=0.6|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.8,"petal_length"=1.9,"petal_width"=0.4|Iris-setosa +"sepal_length"=4.8,"sepal_width"=3.0,"petal_length"=1.4,"petal_width"=0.3|Iris-setosa +"sepal_length"=5.1,"sepal_width"=3.8,"petal_length"=1.6,"petal_width"=0.2|Iris-setosa +"sepal_length"=4.6,"sepal_width"=3.2,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.3,"sepal_width"=3.7,"petal_length"=1.5,"petal_width"=0.2|Iris-setosa +"sepal_length"=5.0,"sepal_width"=3.3,"petal_length"=1.4,"petal_width"=0.2|Iris-setosa +"sepal_length"=7.0,"sepal_width"=3.2,"petal_length"=4.7,"petal_width"=1.4|Iris-versicolor +"sepal_length"=6.4,"sepal_width"=3.2,"petal_length"=4.5,"petal_width"=1.5|Iris-versicolor +"sepal_length"=6.9,"sepal_width"=3.1,"petal_length"=4.9,"petal_width"=1.5|Iris-versicolor +"sepal_length"=5.5,"sepal_width"=2.3,"petal_length"=4.0,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.5,"sepal_width"=2.8,"petal_length"=4.6,"petal_width"=1.5|Iris-versicolor +"sepal_length"=5.7,"sepal_width"=2.8,"petal_length"=4.5,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.3,"sepal_width"=3.3,"petal_length"=4.7,"petal_width"=1.6|Iris-versicolor +"sepal_length"=4.9,"sepal_width"=2.4,"petal_length"=3.3,"petal_width"=1.0|Iris-versicolor +"sepal_length"=6.6,"sepal_width"=2.9,"petal_length"=4.6,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.2,"sepal_width"=2.7,"petal_length"=3.9,"petal_width"=1.4|Iris-versicolor +"sepal_length"=5.0,"sepal_width"=2.0,"petal_length"=3.5,"petal_width"=1.0|Iris-versicolor +"sepal_length"=5.9,"sepal_width"=3.0,"petal_length"=4.2,"petal_width"=1.5|Iris-versicolor +"sepal_length"=6.0,"sepal_width"=2.2,"petal_length"=4.0,"petal_width"=1.0|Iris-versicolor +"sepal_length"=6.1,"sepal_width"=2.9,"petal_length"=4.7,"petal_width"=1.4|Iris-versicolor +"sepal_length"=5.6,"sepal_width"=2.9,"petal_length"=3.6,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.7,"sepal_width"=3.1,"petal_length"=4.4,"petal_width"=1.4|Iris-versicolor +"sepal_length"=5.6,"sepal_width"=3.0,"petal_length"=4.5,"petal_width"=1.5|Iris-versicolor +"sepal_length"=5.8,"sepal_width"=2.7,"petal_length"=4.1,"petal_width"=1.0|Iris-versicolor +"sepal_length"=6.2,"sepal_width"=2.2,"petal_length"=4.5,"petal_width"=1.5|Iris-versicolor +"sepal_length"=5.6,"sepal_width"=2.5,"petal_length"=3.9,"petal_width"=1.1|Iris-versicolor +"sepal_length"=5.9,"sepal_width"=3.2,"petal_length"=4.8,"petal_width"=1.8|Iris-versicolor +"sepal_length"=6.1,"sepal_width"=2.8,"petal_length"=4.0,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.3,"sepal_width"=2.5,"petal_length"=4.9,"petal_width"=1.5|Iris-versicolor +"sepal_length"=6.1,"sepal_width"=2.8,"petal_length"=4.7,"petal_width"=1.2|Iris-versicolor +"sepal_length"=6.4,"sepal_width"=2.9,"petal_length"=4.3,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.6,"sepal_width"=3.0,"petal_length"=4.4,"petal_width"=1.4|Iris-versicolor +"sepal_length"=6.8,"sepal_width"=2.8,"petal_length"=4.8,"petal_width"=1.4|Iris-versicolor +"sepal_length"=6.7,"sepal_width"=3.0,"petal_length"=5.0,"petal_width"=1.7|Iris-versicolor +"sepal_length"=6.0,"sepal_width"=2.9,"petal_length"=4.5,"petal_width"=1.5|Iris-versicolor +"sepal_length"=5.7,"sepal_width"=2.6,"petal_length"=3.5,"petal_width"=1.0|Iris-versicolor +"sepal_length"=5.5,"sepal_width"=2.4,"petal_length"=3.8,"petal_width"=1.1|Iris-versicolor +"sepal_length"=5.5,"sepal_width"=2.4,"petal_length"=3.7,"petal_width"=1.0|Iris-versicolor +"sepal_length"=5.8,"sepal_width"=2.7,"petal_length"=3.9,"petal_width"=1.2|Iris-versicolor +"sepal_length"=6.0,"sepal_width"=2.7,"petal_length"=5.1,"petal_width"=1.6|Iris-versicolor +"sepal_length"=5.4,"sepal_width"=3.0,"petal_length"=4.5,"petal_width"=1.5|Iris-versicolor +"sepal_length"=6.0,"sepal_width"=3.4,"petal_length"=4.5,"petal_width"=1.6|Iris-versicolor +"sepal_length"=6.7,"sepal_width"=3.1,"petal_length"=4.7,"petal_width"=1.5|Iris-versicolor +"sepal_length"=6.3,"sepal_width"=2.3,"petal_length"=4.4,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.6,"sepal_width"=3.0,"petal_length"=4.1,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.5,"sepal_width"=2.5,"petal_length"=4.0,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.5,"sepal_width"=2.6,"petal_length"=4.4,"petal_width"=1.2|Iris-versicolor +"sepal_length"=6.1,"sepal_width"=3.0,"petal_length"=4.6,"petal_width"=1.4|Iris-versicolor +"sepal_length"=5.8,"sepal_width"=2.6,"petal_length"=4.0,"petal_width"=1.2|Iris-versicolor +"sepal_length"=5.0,"sepal_width"=2.3,"petal_length"=3.3,"petal_width"=1.0|Iris-versicolor +"sepal_length"=5.6,"sepal_width"=2.7,"petal_length"=4.2,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.7,"sepal_width"=3.0,"petal_length"=4.2,"petal_width"=1.2|Iris-versicolor +"sepal_length"=5.7,"sepal_width"=2.9,"petal_length"=4.2,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.2,"sepal_width"=2.9,"petal_length"=4.3,"petal_width"=1.3|Iris-versicolor +"sepal_length"=5.1,"sepal_width"=2.5,"petal_length"=3.0,"petal_width"=1.1|Iris-versicolor +"sepal_length"=5.7,"sepal_width"=2.8,"petal_length"=4.1,"petal_width"=1.3|Iris-versicolor +"sepal_length"=6.3,"sepal_width"=3.3,"petal_length"=6.0,"petal_width"=2.5|Iris-virginica +"sepal_length"=5.8,"sepal_width"=2.7,"petal_length"=5.1,"petal_width"=1.9|Iris-virginica +"sepal_length"=7.1,"sepal_width"=3.0,"petal_length"=5.9,"petal_width"=2.1|Iris-virginica +"sepal_length"=6.3,"sepal_width"=2.9,"petal_length"=5.6,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.5,"sepal_width"=3.0,"petal_length"=5.8,"petal_width"=2.2|Iris-virginica +"sepal_length"=7.6,"sepal_width"=3.0,"petal_length"=6.6,"petal_width"=2.1|Iris-virginica +"sepal_length"=4.9,"sepal_width"=2.5,"petal_length"=4.5,"petal_width"=1.7|Iris-virginica +"sepal_length"=7.3,"sepal_width"=2.9,"petal_length"=6.3,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.7,"sepal_width"=2.5,"petal_length"=5.8,"petal_width"=1.8|Iris-virginica +"sepal_length"=7.2,"sepal_width"=3.6,"petal_length"=6.1,"petal_width"=2.5|Iris-virginica +"sepal_length"=6.5,"sepal_width"=3.2,"petal_length"=5.1,"petal_width"=2.0|Iris-virginica +"sepal_length"=6.4,"sepal_width"=2.7,"petal_length"=5.3,"petal_width"=1.9|Iris-virginica +"sepal_length"=6.8,"sepal_width"=3.0,"petal_length"=5.5,"petal_width"=2.1|Iris-virginica +"sepal_length"=5.7,"sepal_width"=2.5,"petal_length"=5.0,"petal_width"=2.0|Iris-virginica +"sepal_length"=5.8,"sepal_width"=2.8,"petal_length"=5.1,"petal_width"=2.4|Iris-virginica +"sepal_length"=6.4,"sepal_width"=3.2,"petal_length"=5.3,"petal_width"=2.3|Iris-virginica +"sepal_length"=6.5,"sepal_width"=3.0,"petal_length"=5.5,"petal_width"=1.8|Iris-virginica +"sepal_length"=7.7,"sepal_width"=3.8,"petal_length"=6.7,"petal_width"=2.2|Iris-virginica +"sepal_length"=7.7,"sepal_width"=2.6,"petal_length"=6.9,"petal_width"=2.3|Iris-virginica +"sepal_length"=6.0,"sepal_width"=2.2,"petal_length"=5.0,"petal_width"=1.5|Iris-virginica +"sepal_length"=6.9,"sepal_width"=3.2,"petal_length"=5.7,"petal_width"=2.3|Iris-virginica +"sepal_length"=5.6,"sepal_width"=2.8,"petal_length"=4.9,"petal_width"=2.0|Iris-virginica +"sepal_length"=7.7,"sepal_width"=2.8,"petal_length"=6.7,"petal_width"=2.0|Iris-virginica +"sepal_length"=6.3,"sepal_width"=2.7,"petal_length"=4.9,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.7,"sepal_width"=3.3,"petal_length"=5.7,"petal_width"=2.1|Iris-virginica +"sepal_length"=7.2,"sepal_width"=3.2,"petal_length"=6.0,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.2,"sepal_width"=2.8,"petal_length"=4.8,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.1,"sepal_width"=3.0,"petal_length"=4.9,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.4,"sepal_width"=2.8,"petal_length"=5.6,"petal_width"=2.1|Iris-virginica +"sepal_length"=7.2,"sepal_width"=3.0,"petal_length"=5.8,"petal_width"=1.6|Iris-virginica +"sepal_length"=7.4,"sepal_width"=2.8,"petal_length"=6.1,"petal_width"=1.9|Iris-virginica +"sepal_length"=7.9,"sepal_width"=3.8,"petal_length"=6.4,"petal_width"=2.0|Iris-virginica +"sepal_length"=6.4,"sepal_width"=2.8,"petal_length"=5.6,"petal_width"=2.2|Iris-virginica +"sepal_length"=6.3,"sepal_width"=2.8,"petal_length"=5.1,"petal_width"=1.5|Iris-virginica +"sepal_length"=6.1,"sepal_width"=2.6,"petal_length"=5.6,"petal_width"=1.4|Iris-virginica +"sepal_length"=7.7,"sepal_width"=3.0,"petal_length"=6.1,"petal_width"=2.3|Iris-virginica +"sepal_length"=6.3,"sepal_width"=3.4,"petal_length"=5.6,"petal_width"=2.4|Iris-virginica +"sepal_length"=6.4,"sepal_width"=3.1,"petal_length"=5.5,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.0,"sepal_width"=3.0,"petal_length"=4.8,"petal_width"=1.8|Iris-virginica +"sepal_length"=6.9,"sepal_width"=3.1,"petal_length"=5.4,"petal_width"=2.1|Iris-virginica +"sepal_length"=6.7,"sepal_width"=3.1,"petal_length"=5.6,"petal_width"=2.4|Iris-virginica +"sepal_length"=6.9,"sepal_width"=3.1,"petal_length"=5.1,"petal_width"=2.3|Iris-virginica +"sepal_length"=5.8,"sepal_width"=2.7,"petal_length"=5.1,"petal_width"=1.9|Iris-virginica +"sepal_length"=6.8,"sepal_width"=3.2,"petal_length"=5.9,"petal_width"=2.3|Iris-virginica +"sepal_length"=6.7,"sepal_width"=3.3,"petal_length"=5.7,"petal_width"=2.5|Iris-virginica +"sepal_length"=6.7,"sepal_width"=3.0,"petal_length"=5.2,"petal_width"=2.3|Iris-virginica +"sepal_length"=6.3,"sepal_width"=2.5,"petal_length"=5.0,"petal_width"=1.9|Iris-virginica +"sepal_length"=6.5,"sepal_width"=3.0,"petal_length"=5.2,"petal_width"=2.0|Iris-virginica +"sepal_length"=6.2,"sepal_width"=3.4,"petal_length"=5.4,"petal_width"=2.3|Iris-virginica +"sepal_length"=5.9,"sepal_width"=3.0,"petal_length"=5.1,"petal_width"=1.8|Iris-virginica diff --git a/pyminer2/tests/datasets/lenses.tab b/pyminer2/tests/datasets/lenses.tab new file mode 100644 index 0000000000000000000000000000000000000000..87dffb64ded0792f0618c5d8a2fe214440c02a47 --- /dev/null +++ b/pyminer2/tests/datasets/lenses.tab @@ -0,0 +1,27 @@ +age prescription astigmatic tear_rate lenses +discrete discrete discrete discrete discrete + class +young myope no reduced none +young myope no normal soft +young myope yes reduced none +young myope yes normal hard +young hypermetrope no reduced none +young hypermetrope no normal soft +young hypermetrope yes reduced none +young hypermetrope yes normal hard +pre-presbyopic myope no reduced none +pre-presbyopic myope no normal soft +pre-presbyopic myope yes reduced none +pre-presbyopic myope yes normal hard +pre-presbyopic hypermetrope no reduced none +pre-presbyopic hypermetrope no normal soft +pre-presbyopic hypermetrope yes reduced none +pre-presbyopic hypermetrope yes normal none +presbyopic myope no reduced none +presbyopic myope no normal none +presbyopic myope yes reduced none +presbyopic myope yes normal hard +presbyopic hypermetrope no reduced none +presbyopic hypermetrope no normal soft +presbyopic hypermetrope yes reduced none +presbyopic hypermetrope yes normal none diff --git a/pyminer2/tests/datasets/sailing-orange-3-20.pkl b/pyminer2/tests/datasets/sailing-orange-3-20.pkl new file mode 100644 index 0000000000000000000000000000000000000000..031207048d35fbe81ca961cf398e7fadaa0683b7 Binary files /dev/null and b/pyminer2/tests/datasets/sailing-orange-3-20.pkl differ diff --git a/pyminer2/tests/datasets/sailing-orange-3-20.pkl.gz b/pyminer2/tests/datasets/sailing-orange-3-20.pkl.gz new file mode 100644 index 0000000000000000000000000000000000000000..eaf74dcf3e032cd29f039ed6df3423d44ab34ab8 Binary files /dev/null and b/pyminer2/tests/datasets/sailing-orange-3-20.pkl.gz differ diff --git a/pyminer2/tests/datasets/sailing-orange-3-21.pkl b/pyminer2/tests/datasets/sailing-orange-3-21.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6c577e1621331af35ef5a43c3faaeabca624b4d3 Binary files /dev/null and b/pyminer2/tests/datasets/sailing-orange-3-21.pkl differ diff --git a/pyminer2/tests/datasets/sailing-orange-3-21.pkl.gz b/pyminer2/tests/datasets/sailing-orange-3-21.pkl.gz new file mode 100644 index 0000000000000000000000000000000000000000..3052defd5ae9f1cd1eb7ff1b18386db8d947c543 Binary files /dev/null and b/pyminer2/tests/datasets/sailing-orange-3-21.pkl.gz differ diff --git a/pyminer2/tests/datasets/test1.tab b/pyminer2/tests/datasets/test1.tab new file mode 100644 index 0000000000000000000000000000000000000000..532481be74b2a9a4edefe168f8a6647021509afc --- /dev/null +++ b/pyminer2/tests/datasets/test1.tab @@ -0,0 +1,6 @@ +a b c X d e +d c 1 0 d d j l + i class +A 0 0 i t i +B 1.1 1 j t j +C 2.22 1 k f k diff --git a/pyminer2/tests/datasets/test10.tab b/pyminer2/tests/datasets/test10.tab new file mode 100644 index 0000000000000000000000000000000000000000..338a73bec3bcd03e84d9345c155a2b4e23b4285e --- /dev/null +++ b/pyminer2/tests/datasets/test10.tab @@ -0,0 +1,6 @@ +c1 c2 d1 d2 n1 n2 c3 d3 c4 cl1 cl2 +c t d d c d c d c d c + class class +1 1995-01-21 a a ? a 2 a a 2 +1 2003-07-23 a b 1 ? 0 b b 0 +1 1967-03-12 a b 2 b -2 c c 1 diff --git a/pyminer2/tests/datasets/test2.tab b/pyminer2/tests/datasets/test2.tab new file mode 100644 index 0000000000000000000000000000000000000000..3b23daf50828ed6a6f781093ef05ebff6dd06350 --- /dev/null +++ b/pyminer2/tests/datasets/test2.tab @@ -0,0 +1,12 @@ +a b c X d e +d c 1 0 d d s +m i class +A 0 0 i t i +B 1.1 1 j t j +C 2.22 1 k f k +C 2.23 1 k f k +C 2.24 1 k f k +C 2.25 1 k f k +C 2.26 1 k f k +D 3.333 +E ? ? k f k diff --git a/pyminer2/tests/datasets/test3.tab b/pyminer2/tests/datasets/test3.tab new file mode 100644 index 0000000000000000000000000000000000000000..fbb2574a48cc0b78dc612b628c32e6e334d300e3 --- /dev/null +++ b/pyminer2/tests/datasets/test3.tab @@ -0,0 +1,4 @@ +a b c X d e +d c 1 0 d d s +m i m + diff --git a/pyminer2/tests/datasets/test4.tab b/pyminer2/tests/datasets/test4.tab new file mode 100644 index 0000000000000000000000000000000000000000..4c7983c7bc9c5b4e1f81b5829b65ec1725df9cd6 --- /dev/null +++ b/pyminer2/tests/datasets/test4.tab @@ -0,0 +1,6 @@ +c1 c2 d1 d2 d3 cl1 +c c d d d d + class +1 -2 a a a a +0 0 a b b b +2 2 a b c c diff --git a/pyminer2/tests/datasets/test5.tab b/pyminer2/tests/datasets/test5.tab new file mode 100644 index 0000000000000000000000000000000000000000..3e2de340fa97d323cb7a48f0a664df64ab9af52e --- /dev/null +++ b/pyminer2/tests/datasets/test5.tab @@ -0,0 +1,6 @@ +c1 c2 d1 d2 n1 n2 c3 d3 c4 cl1 cl2 +c c d d c d c d c d c + class class +1 2 a a ? a 2 a a 2 +1 0 a b 1 ? 0 b b 0 +1 1 a b 2 b -2 c c 1 \ No newline at end of file diff --git a/pyminer2/tests/datasets/test8.tab b/pyminer2/tests/datasets/test8.tab new file mode 100644 index 0000000000000000000000000000000000000000..2517ba49dca2a0cb7ae712051665fa52d3538408 --- /dev/null +++ b/pyminer2/tests/datasets/test8.tab @@ -0,0 +1,6 @@ +c1 c0 d1 d0 cl1 cl0 cl3 cl4 +c c d d d c d c + class class class class +1 2 1 6 3 2 2 1 +1 0 1 4 2 0 2 1 +1 1 1 4 1 1 2 1 diff --git a/pyminer2/tests/datasets/test9.tab b/pyminer2/tests/datasets/test9.tab new file mode 100644 index 0000000000000000000000000000000000000000..b536386e014e603f25bec32eb99a24cfd1f3b2dd --- /dev/null +++ b/pyminer2/tests/datasets/test9.tab @@ -0,0 +1 @@ +a b c d e f g d d d d string d string meta meta meta meta meta 1 1 1 1 1 1 1 1 2 2 1 2 1 1 1 3 3 1 3 1 huh 1 4 4 2 4 hey hoy 2 5 5 2 5 2 2 6 6 2 6 2 2 2 7 7 3 7 3 oh yeah 2 8 8 3 8 3 3 \ No newline at end of file diff --git a/pyminer2/tests/datasets/test_asn_data_working.csv b/pyminer2/tests/datasets/test_asn_data_working.csv new file mode 100644 index 0000000000000000000000000000000000000000..58231b22a83f331daf77b24b99e4fea47374061b --- /dev/null +++ b/pyminer2/tests/datasets/test_asn_data_working.csv @@ -0,0 +1,9 @@ +PAGE DATE DATE_ISO DATE_ISO_CLEANED DECADE YEAR MONTH ID TYPE REGISTRATION OPERATOR FATALITIES FATALITIES_CLEANED LOCATION CATEGORY +1 18.08.26 1926-08-18 1926-08-18 1920 1926 8 19260818-0 Blériot 155 F-AIEB Air Union 4 4 Hurst, near ... A1 +1 02-OCT-1926 1926-10-02 1926-10-02 1920 1926 10 19261002-0 Blériot 155 F-AICQ Air Union 7 7 Leigh, Kent A1 +1 22.08.27 1927-08-22 1927-08-22 1920 1927 8 19270822-0 Fokker F.VIII H-NADU KLM 1 1 St. Julians,... A1 +1 15.02.28 1928-02-15 1928-02-15 1920 1928 2 19280215-0 Handley Page W.8b G-EBBG Imperial Airways 0 0 near Abbeville A1 +1 11-MAR-1928 1928-03-11 1928-03-11 1920 1928 3 19280311-0 Farman F.60 Goliath F-AEFC Air Union 2 2 near Folkestone, ... A1 +1 11.04.28 1928-04-11 1928-04-11 1920 1928 4 19280411-0 Fokker F.VIII H-NAEE KLM 0 0 Nigtevecht A1 +1 12-MAY-1928 1928-05-12 1928-05-12 1920 1928 5 19280512-0 Ford 4-AT-A Tri-Motor NC1492 Ford Air Freight Lines 2 2 Dearborn, MI A1 +1 23-MAY-1928 1928-05-23 1928-05-23 1920 1928 5 19280523-0 Farman F.63bis Goliath F-AEIE SGTA 3 3 near Köln-Butzwei... A1 diff --git a/pyminer2/tests/datasets/weird.tab b/pyminer2/tests/datasets/weird.tab new file mode 100644 index 0000000000000000000000000000000000000000..7a449317714c2a0e30d827506fa4880bc2ab2ff0 --- /dev/null +++ b/pyminer2/tests/datasets/weird.tab @@ -0,0 +1,9 @@ +['5534fab7fad58d5df50061f1', '5534fab8fad58d5de20061f8'] DDB +c string +Timepoint=20 id=['5534fab7fad58d5df50061f1',\ '5534fab8fad58d5de20061f8'] Name=['Gene\ expressions\ (dd_AX4_on_Ka_20Hr_bio1_mapped.bam)',\ 'Gene\ expressions\ (dd_AX4_on_Ka_20Hr_bio2_mapped.bam)'] Replicate=['1',\ '2'] m +2.219 DDB_G0267178 +1.055 DDB_G0267180 +3.271 DDB_G0267182 +2.123 DDB_G0267184 +1.566 DDB_G0267186 +3.111 DDB_G0267188 diff --git a/pyminer2/tests/datasets/zoo-with-images.tab b/pyminer2/tests/datasets/zoo-with-images.tab new file mode 100644 index 0000000000000000000000000000000000000000..68b253f9b09247952604c5414bead36e112dd7fb --- /dev/null +++ b/pyminer2/tests/datasets/zoo-with-images.tab @@ -0,0 +1 @@ +catsize predator aquatic fins feathers type name images d d d d d d string string class meta meta type=image 1 0 0 0 0 mammal antelope http://i.imgur.com/l4DYQJb.png 0 1 1 1 0 fish bass http://i.imgur.com/Kd5uTYY.jpg 1 1 0 0 0 mammal bear http://i.imgur.com/RshdH5C.png 1 1 0 0 0 mammal boar http://i.imgur.com/aeU9kSt.jpg 0 0 1 1 0 fish carp http://i.imgur.com/4fA4ky7.jpg 0 1 1 1 0 fish catfish http://i.imgur.com/lKFiWKu.jpg 0 0 0 0 1 bird chicken http://i.imgur.com/Vk9M2vk.jpg 1 0 0 0 0 mammal deer http://i.imgur.com/VdyeyIu.png 1 1 1 1 0 mammal dolphin http://i.imgur.com/1zBVYru.jpg 0 0 1 0 1 bird duck http://i.imgur.com/9nl7YSS.jpg 0 1 1 0 1 bird gull http://i.imgur.com/ahRl1X7.jpg 0 0 1 1 0 fish haddock http://i.imgur.com/eZaWykE.jpg 0 0 0 0 0 mammal hamster http://i.imgur.com/6c4GURB.jpg 0 1 0 0 1 bird kiwi http://i.imgur.com/3Fao7gt.jpg 1 1 1 0 0 mammal mink http://i.imgur.com/ldX54Ww.jpg \ No newline at end of file diff --git a/pyminer2/tests/dummy_learners.py b/pyminer2/tests/dummy_learners.py new file mode 100644 index 0000000000000000000000000000000000000000..133547ff9e7505488890dec7d1e7f15c4e80f028 --- /dev/null +++ b/pyminer2/tests/dummy_learners.py @@ -0,0 +1,67 @@ +import numpy as np + +from Orange.classification import SklLearner, SklModel +from Orange.classification.base_classification import SklModelClassification + + +class DummyLearner(SklLearner): + def fit(self, X, Y, W): + rows = Y.shape[0] + value = Y[np.random.randint(0, rows)] + class_vals = np.unique(Y) + prob = (class_vals == value) * 0.8 + 0.1 + return DummyPredictor(value, prob) + + +class DummySklModel: + def __init__(self, value, prob): + self.value = value + self.prob = prob + + def predict(self, X): + return np.tile(self.value, len(X)) + + def predict_proba(self, X): + return np.tile(self.prob, (len(X), 1)) + + +class DummyPredictor(SklModelClassification): + def __init__(self, value, prob): + SklModel.__init__(self, DummySklModel(value, prob)) + + +class DummyMulticlassLearner(SklLearner): + supports_multiclass = True + + def check_learner_adequacy(self, domain): + return all(c.is_discrete for c in domain.class_vars) + + def fit(self, X, Y, W): + rows, class_vars = Y.shape + rid = np.random.randint(0, rows) + value = [Y[rid, cid] for cid in range(Y.shape[1])] + used_vals = [np.unique(y) for y in Y.T] + max_vals = max(len(np.unique(y)) for y in Y.T) + prob = np.zeros((class_vars, max_vals)) + for c in range(class_vars): + class_prob = (used_vals[c] == value[c]) * 0.8 + 0.1 + prob[c, :] = np.hstack((class_prob, + np.zeros(max_vals - len(class_prob)))) + return DummyMulticlassPredictor(value, prob) + + +class DummySklMulticlassModel: + def __init__(self, value, prob): + self.value = value + self.prob = prob + + def predict(self, X): + return np.tile(self.value, (len(X), 1)) + + def predict_proba(self, X): + return np.tile(self.prob, (len(X), 1, 1)) + + +class DummyMulticlassPredictor(SklModelClassification): + def __init__(self, value, prob): + SklModel.__init__(self, DummySklMulticlassModel(value, prob)) diff --git a/pyminer2/tests/sql/__init__.py b/pyminer2/tests/sql/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pyminer2/tests/sql/base.py b/pyminer2/tests/sql/base.py new file mode 100644 index 0000000000000000000000000000000000000000..c0ff2fa16454b2834cc63f7185bb2b1bdb0b4b0b --- /dev/null +++ b/pyminer2/tests/sql/base.py @@ -0,0 +1,455 @@ +import os +import string +import unittest +from urllib import parse +import random +import inspect + +import numpy as np + +from Orange.data import Table + + +def parse_uri(uri): + """Parse uri to db type and dictionary of connection parameters.""" + if uri == "": + return "", dict() + parsed_uri = parse.urlparse(uri) + database = parsed_uri.path.strip('/') + if "/" in database: + database, table = database.split('/', 1) + else: + table = "" + + params = parse.parse_qs(parsed_uri.query) + for key, value in params.items(): + if len(params[key]) == 1: + params[key] = value[0] + + params.update(dict( + host=parsed_uri.hostname, + port=parsed_uri.port, + user=parsed_uri.username, + database=database, + password=parsed_uri.password, + )) + if table: + params['table'] = table + return parsed_uri.scheme, params + + +class TestParseUri(unittest.TestCase): + def test_parses_connection_uri(self): + parameters = parse_uri( + "sql://user:password@host:7678/database/table") + + self.assertEqual("sql", parameters[0]) + self.assertDictContainsSubset(dict( + host="host", + user="user", + password="password", + port=7678, + database="database", + table="table" + ), parameters[1]) + + def test_parse_minimal_connection_uri(self): + parameters = parse_uri( + "sql://host/database/table") + + self.assertEqual("sql", parameters[0]) + self.assertDictContainsSubset( + dict(host="host", database="database", table="table"), + parameters[1] + ) + + def test_parse_empty(self): + parameters = parse_uri("") + + self.assertEqual("", parameters[0]) + self.assertDictContainsSubset( + dict(), + parameters[1] + ) + + def assertDictContainsSubset(self, subset, dictionary, msg=None): + """Checks whether dictionary is a superset of subset. + + This method has been copied from unittest/case.py and undeprecated. + """ + from unittest.case import safe_repr + + missing = [] + mismatched = [] + for key, value in subset.items(): + if key not in dictionary: + missing.append(key) + elif value != dictionary[key]: + mismatched.append('%s, expected: %s, actual: %s' % + (safe_repr(key), safe_repr(value), + safe_repr(dictionary[key]))) + + if not (missing or mismatched): + return + + standardMsg = '' + if missing: + standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in + missing) + if mismatched: + if standardMsg: + standardMsg += '; ' + standardMsg += 'Mismatched values: %s' % ','.join(mismatched) + + self.fail(self._formatMessage(msg, standardMsg)) + + +def connection_params(): + """ + Get environment variable that holds db connection parameters. + You can assign multiple connections by concatenating them with '|'. + """ + dburi = os.environ.get('ORANGE_TEST_DB_URI', "") + return dict(parse_uri(uri) for uri in dburi.split("|")) + + +class DBTestConnection: + """Used to prepare the connection to the database""" + uri_name = "" + module = "" + + def __init__(self, params): + self._params = params + self.is_module = False + self.is_active = False + self.try_connection() + + @property + def params(self): + return self._params.copy() + + def try_connection(self): + """ + Test if db specific connection module is installed and if you can + connect to db. + """ + raise NotImplementedError() + + def create_sql_table(self, data, sql_column_types=None, + sql_column_names=None, table_name=None): + """This creates a new sql table in the specific db.""" + raise NotImplementedError() + + @staticmethod + def _get_column_types(data): + if not data: + return [0] * 3 + column_size = [0] * len(data[0]) + for row in data: + for i, value in enumerate(row): + if isinstance(value, str): + column_size[i] = max(len(value), column_size[i]) + + return column_size + + def drop_sql_table(self, table_name): + """This drops given sql table in the specific db.""" + raise NotImplementedError + + def get_backend(self): + """This returns the db specific Orange Backend.""" + raise NotImplementedError + + +class PostgresTestConnection(DBTestConnection): + uri_name = "postgres" + module = "psycopg2" + + def try_connection(self): + try: + import psycopg2 + self.is_module = True + with psycopg2.connect(**self.params) as conn: + self.is_active = True + self.version = conn.server_version + except: + pass + + def create_sql_table(self, data, sql_column_types=None, + sql_column_names=None, table_name=None): + data = list(data) + + if table_name is None: + table_name = ''.join(random.choices(string.ascii_lowercase, k=16)) + + if sql_column_types is None: + column_size = self._get_column_types(data) + sql_column_types = [ + 'float' if size == 0 else 'varchar({})'.format(size) + for size in column_size + ] + + if sql_column_names is None: + sql_column_names = ["col{}".format(i) + for i in range(len(sql_column_types))] + else: + sql_column_names = map(lambda x: '"{}"'.format(x), sql_column_names) + + drop_table_sql = "DROP TABLE IF EXISTS {}".format(table_name) + + create_table_sql = "CREATE TABLE {} ({})".format( + table_name, + ", ".join('{} {}'.format(n, t) + for n, t in zip(sql_column_names, sql_column_types))) + + insert_values = ", ".join( + "({})".format( + ", ".join("NULL" if v is None else "'{}'".format(v) + for v, t in zip(row, sql_column_types)) + ) for row in data + ) + + insert_sql = "INSERT INTO {} VALUES {}".format(table_name, + insert_values) + + import psycopg2 + with psycopg2.connect(**self.params) as conn: + with conn.cursor() as curs: + curs.execute(drop_table_sql) + with conn.cursor() as curs: + curs.execute(create_table_sql) + if insert_values: + with conn.cursor() as curs: + curs.execute(insert_sql) + + return self.params, table_name + + def drop_sql_table(self, table_name): + import psycopg2 + with psycopg2.connect(**self.params) as conn: + with conn.cursor() as curs: + curs.execute("DROP TABLE {}".format(table_name)) + + def get_backend(self): + from Orange.data.sql.backend import Psycopg2Backend + return Psycopg2Backend(self.params) + + +class MicrosoftTestConnection(DBTestConnection): + uri_name = "mssql" + module = "pymssql" + + def try_connection(self): + try: + import pymssql + self.is_module = True + with pymssql.connect(**self.params): + self.is_active = True + except: + pass + + def create_sql_table(self, data, sql_column_types=None, + sql_column_names=None, table_name=None): + data = list(data) + + if table_name is None: + table_name = ''.join(random.choices(string.ascii_lowercase, k=16)) + + if sql_column_types is None: + column_size = self._get_column_types(data) + sql_column_types = [ + 'float' if size == 0 else 'varchar({})'.format(size) + for size in column_size + ] + + if sql_column_names is None: + sql_column_names = ["col{}".format(i) + for i in range(len(sql_column_types))] + else: + sql_column_names = map(lambda x: '"{}"'.format(x), sql_column_names) + + drop_table_sql = "DROP TABLE IF EXISTS {}".format(table_name) + + create_table_sql = "CREATE TABLE {} ({})".format( + table_name, + ", ".join('{} {}'.format(n, t) + for n, t in zip(sql_column_names, sql_column_types))) + + insert_values = ", ".join( + "({})".format( + ", ".join("NULL" if v is None else "'{}'".format(v) + for v, t in zip(row, sql_column_types)) + ) for row in data + ) + + insert_sql = "INSERT INTO {} VALUES {}".format(table_name, + insert_values) + + import pymssql + with pymssql.connect(**self.params) as conn: + with conn.cursor() as cursor: + cursor.execute(drop_table_sql) + cursor.execute(create_table_sql) + if insert_values: + cursor.execute(insert_sql) + conn.commit() + + return self.params, table_name + + def drop_sql_table(self, table_name): + import pymssql + with pymssql.connect(**self.params) as conn: + with conn.cursor() as cursor: + cursor.execute("DROP TABLE {}".format(table_name)) + conn.commit() + + def get_backend(self): + from Orange.data.sql.backend import PymssqlBackend + return PymssqlBackend(self.params) + + +test_connections = { + PostgresTestConnection.uri_name: PostgresTestConnection, + MicrosoftTestConnection.uri_name: MicrosoftTestConnection +} + + +def dbs(): + """Parse env variable and initialize connection to given dbs.""" + params = connection_params() + + db_conn = {} + for c in params: + if c and c in test_connections: + db_conn[c] = test_connections[c](params[c]) + + return db_conn + + +class DataBaseTest: + db_conn = dbs() + + @classmethod + def _check_db(cls, db): + if ">" in db: + i = db.find(">") + if db[:i] in cls.db_conn and \ + cls.db_conn[db[:i]].version <= int(db[i + 1:]): + raise unittest.SkipTest( + "This test is only run database version higher then {}" + .format(db[i + 1:])) + else: + db = db[:i] + elif "<" in db: + i = db.find("<") + if db[:i] in cls.db_conn and \ + cls.db_conn[db[:i]].version >= int(db[i + 1:]): + raise unittest.SkipTest( + "This test is only run on database version lower then {}" + .format(db[i + 1:])) + else: + db = db[:i] + + if db in cls.db_conn: + if not cls.db_conn[db].is_module: + raise unittest.SkipTest( + "{} module is required for this database".format( + cls.db_conn[db].module)) + + elif not cls.db_conn[db].is_active: + raise unittest.SkipTest("Database is not running") + else: + if db in test_connections.keys(): + raise unittest.SkipTest("No connection provided for {}".format(db)) + else: + raise Exception("Unsupported database") + + return db + + @classmethod + def _setup_test_with(cls, test, db): + """This is used to setup the `db` database and run `test` on it""" + def new_test(test_self, *args): + new_db = cls._check_db(db) + + test_self.current_db = new_db + + error = None + if hasattr(test_self, "setUpDB"): + test_self.setUpDB() + try: + test(test_self, *args) + except Exception as ex: + error = ex + finally: + if hasattr(test_self, "tearDownDB"): + test_self.tearDownDB() + + if error is not None: + raise error + + return new_test + + @classmethod + def run_on(cls, dbs): + """ + Decorator used to create new test for every given database. + + For every db in the list of dbs create a new test that: + * changes create_sql_table, drop_sql_table and backend to those + implemented in the db subclass of DBTestConnection + * runs setUpDB if exists + * runs original test + * runs tearDownDB if exists + """ + def decorator(function): + if function.__name__.startswith("test_db_"): + return function + + stack = inspect.stack() + frame = stack[1] + frame_locals = frame[0].f_locals + + for db in dbs: + name = 'test_db_' + db + '_' + function.__name__[5:] + frame_locals[name] = cls._setup_test_with(function, db) + frame_locals[name].__name__ = name + frame_locals[name].place_as = function + if function.__doc__ is not None: + frame_locals[name].__doc__ = 'On ' + db + ' run: ' + \ + function.__doc__ + + function.__test__ = False + + return decorator + + @property + def backend(self): + """This is according to the db currently being tested""" + return self.db_conn[self.current_db].get_backend() + + def create_sql_table(self, data, sql_column_types=None, + sql_column_names=None, table_name=None): + """This is according to the db currently being tested""" + return self.db_conn[self.current_db]\ + .create_sql_table(data, sql_column_types=sql_column_types, + sql_column_names=sql_column_names, + table_name=table_name) + + def drop_sql_table(self, table_name): + """This is according to the db currently being tested""" + return self.db_conn[self.current_db]\ + .drop_sql_table(table_name=table_name) + + def create_iris_sql_table(self): + iris = Table("iris") + cn = ["sepal length", "sepal width", "petal length", "petal width", + "iris"] + ct = ["float", "float", "float", "float", "varchar(15)"] + Y = np.array(iris.domain.class_var.values)[iris.Y.astype(int)] + data = [list(x) + [y] for x, y in zip(iris.X, Y)] + return self.create_sql_table(data, table_name="iris", + sql_column_names=cn, sql_column_types=ct) + + def drop_iris_sql_table(self): + self.drop_sql_table("iris") diff --git a/pyminer2/tests/sql/test_filter.py b/pyminer2/tests/sql/test_filter.py new file mode 100644 index 0000000000000000000000000000000000000000..23351493e3af08c04bbfe8b81f4b9f66a7e9e202 --- /dev/null +++ b/pyminer2/tests/sql/test_filter.py @@ -0,0 +1,787 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data.sql.table import SqlTable, SqlRowInstance +from Orange.data import filter, domain +from Orange.tests.sql.base import DataBaseTest as dbt + + +class TestIsDefinedSql(unittest.TestCase, dbt): + def setUpDB(self): + self.data = [ + [1, 2, 3, None, 'm'], + [2, 3, 1, 4, 'f'], + [None, None, None, None, None], + [7, None, 3, None, 'f'], + ] + conn, self.table_name = self.create_sql_table(self.data) + self.table = SqlTable(conn, self.table_name, inspect_values=True) + + def tearDownDB(self): + self.drop_sql_table(self.table_name) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_all_columns(self): + filtered_data = filter.IsDefined()(self.table) + correct_data = [row for row in self.data if all(row)] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_selected_columns(self): + filtered_data = filter.IsDefined(columns=[0])(self.table) + correct_data = [row for row in self.data if row[0]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_all_columns_negated(self): + filtered_data = filter.IsDefined(negate=True)(self.table) + correct_data = [row for row in self.data if not all(row)] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_selected_columns_negated(self): + filtered_data = \ + filter.IsDefined(negate=True, columns=[4])(self.table) + correct_data = [row for row in self.data if not row[4]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_can_inherit_is_defined_filter(self): + filtered_data = filter.IsDefined(columns=[1])(self.table) + filtered_data = filtered_data[:, 4] + correct_data = [[row[4]]for row in self.data if row[1]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + +class TestHasClass(unittest.TestCase, dbt): + def setUpDB(self): + self.data = [ + [1, 2, 3, None, 'm'], + [2, 3, 1, 4, 'f'], + [None, None, None, None, None], + [7, None, 3, None, 'f'], + ] + self.conn, self.table_name = self.create_sql_table(self.data) + table = SqlTable(self.conn, self.table_name, inspect_values=True) + variables = table.domain.variables + new_table = table.copy() + new_table.domain = domain.Domain(variables[:-1], variables[-1:]) + self.table = new_table + + def tearDownDB(self): + self.drop_sql_table(self.table_name) + + @dbt.run_on(["postgres", "mssql"]) + def test_has_class(self): + filtered_data = filter.HasClass()(self.table) + correct_data = [row for row in self.data if row[-1]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_negated(self): + filtered_data = filter.HasClass(negate=True)(self.table) + correct_data = [row for row in self.data if not row[-1]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + +class TestSameValueSql(unittest.TestCase, dbt): + def setUpDB(self): + self.data = [ + [1, 2, 3, 'a', 'm'], + [2, None, 1, 'a', 'f'], + [None, 3, 1, 'b', None], + [2, 2, 3, 'b', 'f'], + ] + self.conn, self.table_name = self.create_sql_table(self.data) + self.table = SqlTable(self.conn, self.table_name, inspect_values=True) + + def tearDownDB(self): + self.drop_sql_table(self.table_name) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_continuous_attribute(self): + filtered_data = filter.SameValue(0, 1)(self.table) + correct_data = [row for row in self.data if row[0] == 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_continuous_attribute_with_unknowns(self): + filtered_data = filter.SameValue(1, 2)(self.table) + correct_data = [row for row in self.data if row[1] == 2] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_continuous_attribute_with_unknown_value(self): + filtered_data = filter.SameValue(1, None)(self.table) + correct_data = [row for row in self.data if row[1] is None] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_on_continuous_attribute_negated(self): + filtered_data = filter.SameValue(0, 1, negate=True)(self.table) + correct_data = [row for row in self.data if not row[0] == 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute(self): + filtered_data = filter.SameValue(3, 'a')(self.table) + correct_data = [row for row in self.data if row[3] == 'a'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute_with_unknown_value(self): + filtered_data = filter.SameValue(4, None)(self.table) + correct_data = [row for row in self.data if row[4] is None] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute_with_unknowns(self): + filtered_data = filter.SameValue(4, 'm')(self.table) + correct_data = [row for row in self.data if row[4] == 'm'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute_negated(self): + filtered_data = filter.SameValue(3, 'a', negate=True)(self.table) + correct_data = [row for row in self.data if not row[3] == 'a'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute_value_passed_as_int(self): + values = self.table.domain[3].values + filtered_data = filter.SameValue(3, 0, negate=True)(self.table) + correct_data = [row for row in self.data if not row[3] == values[0]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_on_discrete_attribute_value_passed_as_float(self): + values = self.table.domain[3].values + filtered_data = filter.SameValue(3, 0., negate=True)(self.table) + correct_data = [row for row in self.data if not row[3] == values[0]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + +class TestValuesSql(unittest.TestCase, dbt): + def setUpDB(self): + self.data = [ + [1, 2, 3, 'a', 'm'], + [2, None, 1, 'a', 'f'], + [None, 3, 1, 'b', None], + [2, 2, 3, 'b', 'f'], + ] + conn, self.table_name = self.create_sql_table(self.data) + self.table = SqlTable(conn, self.table_name, inspect_values=True) + + def tearDownDB(self): + self.drop_sql_table(self.table_name) + + @dbt.run_on(["postgres", "mssql"]) + def test_values_filter_with_no_conditions(self): + with self.assertRaises(ValueError): + filter.Values([])(self.table) + + @dbt.run_on(["postgres", "mssql"]) + def test_discrete_value_filter(self): + filtered_data = filter.Values(conditions=[ + filter.FilterDiscrete(3, ['a']) + ])(self.table) + correct_data = [row for row in self.data if row[3] in ['a']] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_discrete_value_filter_with_multiple_values(self): + filtered_data = filter.Values(conditions=[ + filter.FilterDiscrete(3, ['a', 'b']) + ])(self.table) + correct_data = [row for row in self.data if row[3] in ['a', 'b']] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_discrete_value_filter_with_None(self): + filtered_data = filter.Values(conditions=[ + filter.FilterDiscrete(3, None) + ])(self.table) + correct_data = [row for row in self.data if row[3] is not None] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_continuous_value_filter_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.Equal, 1) + ])(self.table) + correct_data = [row for row in self.data if row[0] == 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_not_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.NotEqual, 1) + ])(self.table) + correct_data = [row for row in self.data if row[0] != 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_continuous_value_filter_less(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.Less, 2) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and row[0] < 2] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_less_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.LessEqual, 2) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and row[0] <= 2] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_greater(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.Greater, 1) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and row[0] > 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_greater_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.GreaterEqual, 1) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and row[0] >= 1] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_between(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.Between, 1, 2) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and 1 <= row[0] <= 2] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_continuous_value_filter_outside(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(0, filter.FilterContinuous.Outside, 2, 3) + ])(self.table) + correct_data = [row for row in self.data + if row[0] is not None and not 2 <= row[0] <= 3] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_continuous_value_filter_isdefined(self): + filtered_data = filter.Values(conditions=[ + filter.FilterContinuous(1, filter.FilterContinuous.IsDefined) + ])(self.table) + correct_data = [row for row in self.data if row[1] is not None] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + +class TestFilterStringSql(unittest.TestCase, dbt): + def setUpDB(self): + self.data = [ + [w] for w in "Lorem ipsum dolor sit amet, consectetur adipiscing" + "elit. Vestibulum vel dolor nulla. Etiam elit lectus, mollis nec" + "mattis sed, pellentesque in turpis. Vivamus non nisi dolor. Etiam" + "lacinia dictum purus, in ullamcorper ante vulputate sed. Nullam" + "congue blandit elementum. Donec blandit laoreet posuere. Proin" + "quis augue eget tortor posuere mollis. Fusce vestibulum bibendum" + "neque at convallis. Donec iaculis risus volutpat malesuada" + "vehicula. Ut cursus tempor massa vulputate lacinia. Pellentesque" + "eu tortor sed diam placerat porttitor et volutpat risus. In" + "vulputate rutrum lacus ac sagittis. Suspendisse interdum luctus" + "sem auctor commodo.".split(' ')] + [[None], [None]] + self.conn, self.table_name = self.create_sql_table(self.data) + self.table = SqlTable(self.conn, self.table_name) + + def tearDownDB(self): + self.drop_sql_table(self.table_name) + + @dbt.run_on(["postgres"]) + def test_filter_string_is_defined(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.IsDefined) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] is not None] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_filter_string_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Equal, 'in') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] == 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_equal_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Equal, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] == 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_equal_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Equal, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] == 'Donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_not_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.NotEqual, 'in') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] != 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_not_equal_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.NotEqual, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] != 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_not_equal_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.NotEqual, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] != 'Donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_filter_string_less(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Less, 'A') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0] < 'A'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_less_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Less, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() < 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_less_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Less, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() < 'donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_filter_string_less_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.LessEqual, 'A') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0] <= 'A'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_less_equal_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.LessEqual, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() <= 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_less_equal_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.LessEqual, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() <= 'donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_filter_string_greater(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Greater, 'volutpat') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0] > 'volutpat'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_greater_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Greater, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() > 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_greater_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Greater, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() > 'donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_greater_equal(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.GreaterEqual, 'volutpat') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0] >= 'volutpat'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_greater_equal_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.GreaterEqual, 'In', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() >= 'in'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_greater_equal_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.GreaterEqual, 'donec', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].lower() >= 'donec'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_between(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Between, 'a', 'c') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'a' <= row[0] <= 'c'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_between_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Between, 'I', 'O', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'i' < row[0].lower() <= 'o'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_between_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Between, 'i', 'O', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'i' <= row[0].lower() <= 'o'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_contains(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Contains, 'et') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'et' in row[0]] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_contains_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Contains, 'eT', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'et' in row[0].lower()] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_contains_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Contains, 'do', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and 'do' in row[0].lower()] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_outside(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Outside, 'am', 'di') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and not 'am' < row[0] < 'di'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_outside_case_insensitive(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.Outside, 'd', 'k', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and not 'd' < row[0].lower() < 'k'] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_starts_with(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.StartsWith, 'D') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].startswith('D')] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_starts_with_case_insensitive(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.StartsWith, 'D', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None + and row[0].lower().startswith('d')] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_ends_with(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.EndsWith, 's') + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None and row[0].endswith('s')] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_ends_with_case_insensitive(self): + filtered_data = filter.Values(conditions=[ + filter.FilterString(-1, filter.FilterString.EndsWith, 'S', + case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data + if row[0] is not None + and row[0].lower().endswith('s')] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_list(self): + filtered_data = filter.Values(conditions=[ + filter.FilterStringList(-1, ['et', 'in']) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] in ['et', 'in']] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres"]) + def test_filter_string_list_case_insensitive_value(self): + filtered_data = filter.Values(conditions=[ + filter.FilterStringList(-1, ['Et', 'In'], case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] in ['et', 'in']] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + @dbt.run_on(["postgres", "mssql"]) + def test_filter_string_list_case_insensitive_data(self): + filtered_data = filter.Values(conditions=[ + filter.FilterStringList(-1, ['donec'], case_sensitive=False) + ])(self.table) + correct_data = [SqlRowInstance(filtered_data.domain, row) + for row in self.data if row[0] in ['Donec']] + + self.assertEqual(len(filtered_data), len(correct_data)) + self.assertSequenceEqual(filtered_data, correct_data) + + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/sql/test_misc.py b/pyminer2/tests/sql/test_misc.py new file mode 100644 index 0000000000000000000000000000000000000000..5b321223cca129c837b754804b05e1d92cc3fc85 --- /dev/null +++ b/pyminer2/tests/sql/test_misc.py @@ -0,0 +1,47 @@ +"""Test for miscellaneous sql queries in widgets + +Please note that such use is deprecated. +""" +import unittest + +from Orange.data.sql.table import SqlTable +from Orange.preprocess import Discretize +from Orange.preprocess.discretize import EqualFreq +from Orange.tests.sql.base import DataBaseTest as dbt +try: + from Orange.widgets.visualize.owmosaic import get_conditional_distribution + from Orange.widgets.visualize.utils.lac import \ + create_sql_contingency, get_bin_centers +except ImportError: + no_widgets = True +else: + no_widgets = False + + +class MiscSqlTests(unittest.TestCase, dbt): + def setUpDB(self): + self.conn, self.iris = self.create_iris_sql_table() + + def tearDownDB(self): + self.drop_iris_sql_table() + + @dbt.run_on(["postgres"]) + def test_discretization(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + sepal_length = iris.domain["sepal length"] + EqualFreq(n=4)(iris, sepal_length) + + @dbt.run_on(["postgres"]) + @unittest.skipIf(no_widgets, "Cannot import widgets") + def test_get_conditional_distribution(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + sepal_length = iris.domain["sepal length"] + get_conditional_distribution(iris, [sepal_length]) + get_conditional_distribution(iris, list(iris.domain.variables)) + + @dbt.run_on(["postgres"]) + @unittest.skipIf(no_widgets, "Cannot import widgets") + def test_create_sql_contingency(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + d_iris = Discretize()(iris) + create_sql_contingency(d_iris, [0, 1], get_bin_centers(d_iris)) diff --git a/pyminer2/tests/sql/test_naive_bayes_sql.py b/pyminer2/tests/sql/test_naive_bayes_sql.py new file mode 100644 index 0000000000000000000000000000000000000000..82d77a687476bebda7d0735c659fbd9cb64047f7 --- /dev/null +++ b/pyminer2/tests/sql/test_naive_bayes_sql.py @@ -0,0 +1,39 @@ +import unittest + +from numpy import array + +import Orange.classification.naive_bayes as nb +from Orange import preprocess +from Orange.data.sql.table import SqlTable +from Orange.data import Domain +from Orange.data.variable import DiscreteVariable +from Orange.tests.sql.base import DataBaseTest as dbt + + +class NaiveBayesTest(unittest.TestCase, dbt): + def setUpDB(self): + self.conn, self.iris = self.create_iris_sql_table() + + def tearDownDB(self): + self.drop_iris_sql_table() + + @dbt.run_on(["postgres"]) + def test_NaiveBayes(self): + iris_v = ['Iris-setosa', 'Iris-virginica', 'Iris-versicolor'] + table = SqlTable(self.conn, self.iris, + type_hints=Domain([], + DiscreteVariable("iris", + values=iris_v))) + disc = preprocess.Discretize() + table = disc(table) + bayes = nb.NaiveBayesLearner() + clf = bayes(table) + # Single instance prediction + self.assertEqual(clf(table[0]), table[0].get_class()) + # Table prediction + pred = clf(table) + actual = array([ins.get_class() for ins in table]) + ca = pred == actual + ca = ca.sum() / len(ca) + self.assertGreater(ca, 0.95) + self.assertLess(ca, 1.) diff --git a/pyminer2/tests/sql/test_sql_table.py b/pyminer2/tests/sql/test_sql_table.py new file mode 100644 index 0000000000000000000000000000000000000000..a809e56142025d8758065988de134f0f4769cdbe --- /dev/null +++ b/pyminer2/tests/sql/test_sql_table.py @@ -0,0 +1,717 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import pickle +import contextlib +import unittest.mock +import string + +import numpy as np +from numpy.testing import assert_almost_equal + +from Orange.data.sql.backend.base import BackendError +from Orange.data import filter, ContinuousVariable, DiscreteVariable, \ + StringVariable, TimeVariable, Table, Domain +from Orange.data.sql.table import SqlTable +from Orange.preprocess.discretize import EqualWidth +from Orange.statistics.basic_stats import BasicStats, DomainBasicStats +from Orange.statistics.contingency import Continuous, Discrete, get_contingencies +from Orange.statistics.distribution import get_distributions +from Orange.tests.sql.base import DataBaseTest as dbt + + +class TestSqlTable(unittest.TestCase, dbt): + def setUpDB(self): + self.conn, self.iris = self.create_iris_sql_table() + + def tearDownDB(self): + self.drop_iris_sql_table() + + def float_variable(self, size): + return [i * .1 for i in range(size)] + + def discrete_variable(self, size): + return ["mf"[i % 2] for i in range(size)] + + def string_variable(self, size): + return string.ascii_letters[:size] + + @contextlib.contextmanager + def sql_table_from_data(self, data, guess_values=True): + params, table_name = self.create_sql_table(data) + yield SqlTable(params, table_name, + inspect_values=guess_values) + + self.drop_sql_table(table_name) + + @dbt.run_on(["postgres"]) + def test_constructs_correct_attributes(self): + data = list(zip(self.float_variable(21), + self.discrete_variable(21), + self.string_variable(21))) + with self.sql_table_from_data(data) as table: + self.assertEqual(len(table.domain), 2) + self.assertEqual(len(table.domain.metas), 1) + + float_attr, discrete_attr = table.domain.variables + string_attr, = table.domain.metas + + self.assertIsInstance(float_attr, ContinuousVariable) + self.assertEqual(float_attr.name, "col0") + self.assertTrue('"col0"' in float_attr.to_sql()) + + self.assertIsInstance(discrete_attr, DiscreteVariable) + self.assertEqual(discrete_attr.name, "col1") + self.assertTrue('"col1"' in discrete_attr.to_sql()) + self.assertEqual(discrete_attr.values, ['f', 'm']) + + self.assertIsInstance(string_attr, StringVariable) + self.assertEqual(string_attr.name, "col2") + self.assertTrue('"col2"' in string_attr.to_sql()) + + @dbt.run_on(["postgres"]) + def test_make_attributes(self): + table1 = SqlTable(self.conn, self.iris) + table2 = SqlTable(self.conn, self.iris) + self.assertEqual(table1.domain[0], table2.domain[0]) + + @dbt.run_on(["postgres", "mssql"]) + def test_len(self): + with self.sql_table_from_data(zip(self.float_variable(26))) as table: + self.assertEqual(len(table), 26) + + with self.sql_table_from_data(zip(self.float_variable(0))) as table: + self.assertEqual(len(table), 0) + + @dbt.run_on(["postgres", "mssql"]) + def test_bool(self): + with self.sql_table_from_data(()) as table: + self.assertEqual(bool(table), False) + with self.sql_table_from_data(zip(self.float_variable(1))) as table: + self.assertEqual(bool(table), True) + + @dbt.run_on(["postgres", "mssql"]) + def test_len_with_filter(self): + data = zip(self.discrete_variable(26)) + with self.sql_table_from_data(data) as table: + self.assertEqual(len(table), 26) + + filtered_table = filter.SameValue(table.domain[0], 'm')(table) + self.assertEqual(len(filtered_table), 13) + + table.domain[0].values.append('x') + filtered_table = filter.SameValue(table.domain[0], 'x')(table) + self.assertEqual(len(filtered_table), 0) + + @dbt.run_on(["postgres", "mssql"]) + def test_XY_small(self): + mat = np.random.randint(0, 2, (20, 3)) + conn, table_name = self.create_sql_table(mat) + sql_table = SqlTable(conn, table_name, + type_hints=Domain([], DiscreteVariable( + name='col2', values=['0', '1', '2']))) + assert_almost_equal(sql_table.X, mat[:, :2]) + assert_almost_equal(sql_table.Y.flatten(), mat[:, 2]) + + @dbt.run_on(["postgres", "mssql"]) + @unittest.mock.patch("Orange.data.sql.table.AUTO_DL_LIMIT", 100) + def test_XY_large(self): + from Orange.data.sql.table import AUTO_DL_LIMIT as DLL + mat = np.random.randint(0, 2, (DLL + 100, 3)) + conn, table_name = self.create_sql_table(mat) + sql_table = SqlTable(conn, table_name, + type_hints=Domain([], DiscreteVariable( + name='col2', values=['0', '1', '2']))) + self.assertRaises(ValueError, lambda: sql_table.X) + self.assertRaises(ValueError, lambda: sql_table.Y) + with self.assertRaises(ValueError): + sql_table.download_data(DLL + 10) + # Download partial data + sql_table.download_data(DLL + 10, partial=True) + assert_almost_equal(sql_table.X, mat[:DLL + 10, :2]) + assert_almost_equal(sql_table.Y.flatten()[:DLL + 10], mat[:DLL + 10, 2]) + # Download all data + sql_table.download_data() + assert_almost_equal(sql_table.X, mat[:, :2]) + assert_almost_equal(sql_table.Y.flatten(), mat[:, 2]) + + @dbt.run_on(["postgres", "mssql"]) + def test_download_data(self): + mat = np.random.randint(0, 2, (20, 3)) + conn, table_name = self.create_sql_table(mat) + for member in ('X', 'Y', 'metas', 'W', 'ids'): + sql_table = SqlTable(conn, table_name, + type_hints=Domain([], DiscreteVariable( + name='col2', values=['0', '1', '2']))) + self.assertFalse(getattr(sql_table, member) is None) + # has all necessary class members to create a standard Table + Table.from_table(sql_table.domain, sql_table) + + @dbt.run_on(["postgres", "mssql"]) + def test_query_all(self): + table = SqlTable(self.conn, self.iris, inspect_values=True) + results = list(table) + + self.assertEqual(len(results), 150) + + @dbt.run_on(["postgres", "mssql"]) + def test_unavailable_row(self): + table = SqlTable(self.conn, self.iris) + self.assertRaises(IndexError, lambda: table[151]) + + @dbt.run_on(["postgres", "mssql"]) + def test_query_subset_of_attributes(self): + table = SqlTable(self.conn, self.iris) + attributes = [ + self._mock_attribute("sepal length"), + self._mock_attribute("sepal width"), + self._mock_attribute("double width", '2 * "sepal width"') + ] + results = list(table._query( + attributes + )) + + self.assertSequenceEqual( + results[:5], + [(5.1, 3.5, 7.0), + (4.9, 3.0, 6.0), + (4.7, 3.2, 6.4), + (4.6, 3.1, 6.2), + (5.0, 3.6, 7.2)] + ) + + @dbt.run_on(["postgres"]) + def test_query_subset_of_rows(self): + table = SqlTable(self.conn, self.iris) + all_results = list(table._query()) + + results = list(table._query(rows=range(10))) + self.assertEqual(len(results), 10) + self.assertSequenceEqual(results, all_results[:10]) + + results = list(table._query(rows=range(10))) + self.assertEqual(len(results), 10) + self.assertSequenceEqual(results, all_results[:10]) + + results = list(table._query(rows=slice(None, 10))) + self.assertEqual(len(results), 10) + self.assertSequenceEqual(results, all_results[:10]) + + results = list(table._query(rows=slice(10, None))) + self.assertEqual(len(results), 140) + self.assertSequenceEqual(results, all_results[10:]) + + @dbt.run_on(["postgres", "mssql"]) + def test_getitem_single_value(self): + table = SqlTable(self.conn, self.iris, inspect_values=True) + self.assertAlmostEqual(table[0, 0], 5.1) + + @dbt.run_on(["postgres", "mssql"]) + def test_type_hints(self): + table = SqlTable(self.conn, self.iris, inspect_values=True) + self.assertEqual(len(table.domain), 5) + self.assertEqual(len(table.domain.metas), 0) + table = SqlTable(self.conn, self.iris, inspect_values=True, + type_hints=Domain([], [], metas=[ + StringVariable("iris")])) + self.assertEqual(len(table.domain), 4) + self.assertEqual(len(table.domain.metas), 1) + + @dbt.run_on(["postgres"]) + def test_joins(self): + table = SqlTable( + self.conn, + """SELECT a."sepal length", + b. "petal length", + CASE WHEN b."petal length" < 3 THEN '<' + ELSE '>' + END AS "qualitative petal length" + FROM iris a + INNER JOIN iris b ON a."sepal width" = b."sepal width" + WHERE a."petal width" < 1 + ORDER BY a."sepal length", b. "petal length" ASC""", + type_hints=Domain([DiscreteVariable( + name="qualitative petal length", + values=['<', '>'])], [])) + + self.assertEqual(len(table), 498) + self.assertAlmostEqual(list(table[497]), [5.8, 1.2, 0.]) + + def _mock_attribute(self, attr_name, formula=None): + if formula is None: + formula = '"%s"' % attr_name + + class Attr: + name = attr_name + + @staticmethod + def to_sql(): + return formula + + return Attr + + @dbt.run_on(["postgres"]) + def test_universal_table(self): + _, table_name = self.construct_universal_table() + + SqlTable(self.conn, """ + SELECT + v1.col2 as v1, + v2.col2 as v2, + v3.col2 as v3, + v4.col2 as v4, + v5.col2 as v5 + FROM %(table_name)s v1 + INNER JOIN %(table_name)s v2 ON v2.col0 = v1.col0 AND v2.col1 = 2 + INNER JOIN %(table_name)s v3 ON v3.col0 = v2.col0 AND v3.col1 = 3 + INNER JOIN %(table_name)s v4 ON v4.col0 = v1.col0 AND v4.col1 = 4 + INNER JOIN %(table_name)s v5 ON v5.col0 = v1.col0 AND v5.col1 = 5 + WHERE v1.col1 = 1 + ORDER BY v1.col0 + """ % dict(table_name='"%s"' % table_name)) + + self.drop_sql_table(table_name) + + def construct_universal_table(self): + values = [] + for row in range(1, 6): + for col in range(1, 6): + values.extend((row, col, row * col)) + table = Table.from_numpy(None, np.array(values).reshape((-1, 3))) + return self.create_sql_table(table) + + IRIS_VARIABLE = DiscreteVariable( + "iris", values=['Iris-setosa', 'Iris-virginica', 'Iris-versicolor']) + + @dbt.run_on(["postgres", "mssql"]) + def test_class_var_type_hints(self): + iris = SqlTable(self.conn, self.iris, + type_hints=Domain([], self.IRIS_VARIABLE)) + + self.assertEqual(len(iris.domain.class_vars), 1) + self.assertEqual(iris.domain.class_vars[0].name, 'iris') + + @dbt.run_on(["postgres", "mssql"]) + def test_metas_type_hints(self): + iris = SqlTable(self.conn, self.iris, + type_hints=Domain([], [], metas=[self.IRIS_VARIABLE])) + + self.assertEqual(len(iris.domain.metas), 1) + self.assertEqual(iris.domain.metas[0].name, 'iris') + + @dbt.run_on(["postgres", "mssql"]) + def test_select_all(self): + iris = SqlTable(self.conn, "SELECT * FROM iris", + type_hints=Domain([], self.IRIS_VARIABLE)) + + self.assertEqual(len(iris.domain), 5) + + @dbt.run_on(["postgres"]) + def test_discrete_bigint(self): + table = np.arange(6).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['bigint']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_continous_bigint(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['bigint']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres"]) + def test_discrete_int(self): + table = np.arange(6).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['int']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_continous_int(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['int']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres"]) + def test_discrete_smallint(self): + table = np.arange(6).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['smallint']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_continous_smallint(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['smallint']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres"]) + def test_boolean(self): + table = np.array(['F', 'T', 0, 1, 'False', 'True']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['boolean']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_discrete_char(self): + table = np.array(['M', 'F', 'M', 'F', 'M', 'F']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['char(1)']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres"]) + def test_discrete_bigger_char(self): + """Test if the discrete values are the same for bigger char fields""" + table = np.array(['M', 'F', 'M', 'F', 'M', 'F']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['char(10)']) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertSequenceEqual(sql_table.domain[0].values, ['F', 'M']) + + @dbt.run_on(["postgres", "mssql"]) + def test_meta_char(self): + table = np.array(list('ABCDEFGHIJKLMNOPQRSTUVW')).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['char(1)']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_discrete_varchar(self): + table = np.array(['M', 'F', 'M', 'F', 'M', 'F']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['varchar(1)']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, DiscreteVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_meta_varchar(self): + table = np.array(list('ABCDEFGHIJKLMNOPQRSTUVW')).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['varchar(1)']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + @dbt.run_on(["postgres"]) + def test_time_date(self): + table = np.array(['2014-04-12', '2014-04-13', '2014-04-14', + '2014-04-15', '2014-04-16']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['date']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + @dbt.run_on(["postgres"]) + def test_time_time(self): + table = np.array(['17:39:51', '11:51:48.46', '05:20:21.492149', + '21:47:06', '04:47:35.8']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['time']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + @dbt.run_on(["postgres"]) + def test_time_timetz(self): + table = np.array(['17:39:51+0200', '11:51:48.46+01', '05:20:21.4921', + '21:47:06-0600', '04:47:35.8+0330']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['timetz']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + @dbt.run_on(["postgres"]) + def test_time_timestamp(self): + table = np.array(['2014-07-15 17:39:51.348149', + '2008-10-05 11:51:48.468149', + '2008-11-03 05:20:21.492149', + '2015-01-02 21:47:06.228149', + '2016-04-16 04:47:35.892149']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['timestamp']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + @dbt.run_on(["postgres"]) + def test_time_timestamptz(self): + table = np.array(['2014-07-15 17:39:51.348149+0200', + '2008-10-05 11:51:48.468149+02', + '2008-11-03 05:20:21.492149+01', + '2015-01-02 21:47:06.228149+0100', + '2016-04-16 04:47:35.892149+0330']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['timestamptz']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, TimeVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_double_precision(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['double precision']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_numeric(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['numeric(15, 2)']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres", "mssql"]) + def test_real(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['real']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres"]) + def test_serial(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['serial']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres>90200"]) + def test_smallserial(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['smallserial']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres>90200"]) + def test_bigserial(self): + table = np.arange(25).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['bigserial']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstAttrIsInstance(sql_table, ContinuousVariable) + + @dbt.run_on(["postgres"]) + def test_text(self): + table = np.array(list('ABCDEFGHIJKLMNOPQRSTUVW')).reshape((-1, 1)) + conn, table_name = self.create_sql_table(table, ['text']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + @dbt.run_on(["postgres"]) + def test_other(self): + table = np.array(['bcd4d9c0-361e-bad4-7ceb-0d171cdec981', + '544b7ddc-d861-0201-81c8-9f7ad0bbf531', + 'b35a10f7-7901-f313-ec16-5ad9778040a6', + 'b267c4be-4a26-60b5-e664-737a90a40e93']).reshape(-1, 1) + conn, table_name = self.create_sql_table(table, ['uuid']) + + sql_table = SqlTable(conn, table_name, inspect_values=False) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + sql_table = SqlTable(conn, table_name, inspect_values=True) + self.assertFirstMetaIsInstance(sql_table, StringVariable) + + filters = filter.Values([filter.FilterString(-1, filter.FilterString.Equal, 'foo')]) + self.assertEqual(len(filters(sql_table)), 0) + + @dbt.run_on(["postgres", "mssql"]) + def test_recovers_connection_after_sql_error(self): + conn, table_name = self.create_sql_table( + np.arange(25).reshape((-1, 1))) + sql_table = SqlTable(conn, table_name) + + try: + broken_query = "SELECT 1/%s FROM %s" % ( + sql_table.domain.attributes[0].to_sql(), sql_table.table_name) + with sql_table.backend.execute_sql_query(broken_query) as cur: + cur.fetchall() + except BackendError: + pass + + working_query = "SELECT %s FROM %s" % ( + sql_table.domain.attributes[0].to_sql(), sql_table.table_name) + with sql_table.backend.execute_sql_query(working_query) as cur: + cur.fetchall() + + @dbt.run_on(["postgres"]) + def test_basic_stats(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + stats = BasicStats(iris, iris.domain['sepal length']) + self.assertAlmostEqual(stats.min, 4.3) + self.assertAlmostEqual(stats.max, 7.9) + self.assertAlmostEqual(stats.mean, 5.8, 1) + self.assertEqual(stats.nans, 0) + self.assertEqual(stats.non_nans, 150) + + domain_stats = DomainBasicStats(iris, include_metas=True) + self.assertEqual(len(domain_stats.stats), + len(iris.domain) + len(iris.domain.metas)) + stats = domain_stats['sepal length'] + self.assertAlmostEqual(stats.min, 4.3) + self.assertAlmostEqual(stats.max, 7.9) + self.assertAlmostEqual(stats.mean, 5.8, 1) + self.assertEqual(stats.nans, 0) + self.assertEqual(stats.non_nans, 150) + + @dbt.run_on(["postgres"]) + @unittest.mock.patch("Orange.data.sql.table.LARGE_TABLE", 100) + def test_basic_stats_on_large_data(self): + # By setting LARGE_TABLE to 100, iris will be treated as + # a large table and sampling will be used. As the table + # is actually small, time base sampling should return + # all rows, so the same assertions can be used. + iris = SqlTable(self.conn, self.iris, inspect_values=True) + stats = BasicStats(iris, iris.domain['sepal length']) + self.assertAlmostEqual(stats.min, 4.3) + self.assertAlmostEqual(stats.max, 7.9) + self.assertAlmostEqual(stats.mean, 5.8, 1) + self.assertEqual(stats.nans, 0) + self.assertEqual(stats.non_nans, 150) + + domain_stats = DomainBasicStats(iris, include_metas=True) + self.assertEqual(len(domain_stats.stats), + len(iris.domain) + len(iris.domain.metas)) + stats = domain_stats['sepal length'] + self.assertAlmostEqual(stats.min, 4.3) + self.assertAlmostEqual(stats.max, 7.9) + self.assertAlmostEqual(stats.mean, 5.8, 1) + self.assertEqual(stats.nans, 0) + self.assertEqual(stats.non_nans, 150) + + @dbt.run_on(["postgres", "mssql"]) + def test_distributions(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + + dists = get_distributions(iris) + self.assertEqual(len(dists), 5) + dist = dists[0] + self.assertAlmostEqual(dist.min(), 4.3) + self.assertAlmostEqual(dist.max(), 7.9) + self.assertAlmostEqual(dist.mean(), 5.8, 1) + + @dbt.run_on(["postgres"]) + def test_contingencies(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + iris.domain = Domain(iris.domain[:2] + (EqualWidth()(iris, iris.domain['sepal width']),), + iris.domain['iris']) + + conts = get_contingencies(iris) + self.assertEqual(len(conts), 3) + self.assertIsInstance(conts[0], Continuous) + self.assertIsInstance(conts[1], Continuous) + self.assertIsInstance(conts[2], Discrete) + + @dbt.run_on(["postgres"]) + def test_pickling_restores_connection_pool(self): + iris = SqlTable(self.conn, self.iris, inspect_values=True) + iris2 = pickle.loads(pickle.dumps(iris)) + + self.assertEqual(iris[0], iris2[0]) + + @dbt.run_on(["postgres"]) + def test_list_tables_with_schema(self): + with self.backend.execute_sql_query("DROP SCHEMA IF EXISTS orange_tests CASCADE") as cur: + cur.execute("CREATE SCHEMA orange_tests") + cur.execute("CREATE TABLE orange_tests.efgh (id int)") + cur.execute("INSERT INTO orange_tests.efgh (id) VALUES (1)") + cur.execute("INSERT INTO orange_tests.efgh (id) VALUES (2)") + + try: + tables = self.backend.list_tables("orange_tests") + self.assertTrue(any([t.name == "efgh" for t in tables])) + SqlTable(self.conn, tables[0], inspect_values=True) + finally: + with self.backend.execute_sql_query("DROP SCHEMA IF EXISTS orange_tests CASCADE"): + pass + + def assertFirstAttrIsInstance(self, table, variable_type): + self.assertGreater(len(table.domain), 0) + attr = table.domain[0] + self.assertIsInstance(attr, variable_type) + + def assertFirstMetaIsInstance(self, table, variable_type): + self.assertGreater(len(table.domain.metas), 0) + attr = table.domain[-1] + self.assertIsInstance(attr, variable_type) diff --git a/pyminer2/tests/test__orange.py b/pyminer2/tests/test__orange.py new file mode 100644 index 0000000000000000000000000000000000000000..9f364f51c25d9eb1b7ed1e7c79469580bcd326da --- /dev/null +++ b/pyminer2/tests/test__orange.py @@ -0,0 +1,27 @@ +import unittest +import numpy as np +from Orange.data import _valuecount + + +class test_valuecount(unittest.TestCase): + + def test_valuecount(self): + for a, expected_b in ([[[1, 1, 1, 1], [0.1, 0.2, 0.3, 0.4]], [[1], [1]]], + [[[1, 1, 1, 2], [0.1, 0.2, 0.3, 0.4]], [[1, 2], [0.6, 0.4]]], + [[[0, 1, 1, 1], [0.1, 0.2, 0.3, 0.4]], [[0, 1], [0.1, 0.9]]], + [[[0, 1, 1, 2], [0.1, 0.2, 0.3, 0.4]], [[0, 1, 2], [0.1, 0.5, 0.4]]], + [[[0, 1, 2, 3], [0.1, 0.2, 0.3, 0.4]], None], + [[[0], [0.1]], None], + [np.ones((2, 1)), None]): + a = np.array(a) + b = _valuecount.valuecount(a) + if expected_b is not None: + np.testing.assert_almost_equal(b, expected_b) + else: + np.testing.assert_almost_equal(b, a) + + for value in ([np.array([[0, 1], [2, 3]])], + [np.ones(2)], + [np.ones((3, 3))], + None): + self.assertRaises(TypeError, _valuecount.valuecount, value) diff --git a/pyminer2/tests/test_ada_boost.py b/pyminer2/tests/test_ada_boost.py new file mode 100644 index 0000000000000000000000000000000000000000..c10f3af63b998e52d774bd7fc57df35edb455c9b --- /dev/null +++ b/pyminer2/tests/test_ada_boost.py @@ -0,0 +1,105 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np +from Orange.data import Table +from Orange.classification import SklTreeLearner +from Orange.regression import SklTreeRegressionLearner +from Orange.ensembles import ( + SklAdaBoostClassificationLearner, + SklAdaBoostRegressionLearner, +) +from Orange.evaluation import CrossValidation, CA, RMSE + + +class TestSklAdaBoostLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table("iris") + cls.housing = Table("housing") + + def test_adaboost(self): + learn = SklAdaBoostClassificationLearner() + cv = CrossValidation(k=3) + results = cv(self.iris, [learn]) + ca = CA(results) + self.assertGreater(ca, 0.9) + self.assertLess(ca, 0.99) + + def test_adaboost_base_estimator(self): + np.random.seed(0) + stump_estimator = SklTreeLearner(max_depth=1) + tree_estimator = SklTreeLearner() + stump = SklAdaBoostClassificationLearner( + base_estimator=stump_estimator, n_estimators=5) + tree = SklAdaBoostClassificationLearner( + base_estimator=tree_estimator, n_estimators=5) + cv = CrossValidation(k=4) + results = cv(self.iris, [stump, tree]) + ca = CA(results) + self.assertLessEqual(ca[0], ca[1]) + + def test_predict_single_instance(self): + learn = SklAdaBoostClassificationLearner() + m = learn(self.iris) + ins = self.iris[0] + m(ins) + _, _ = m(ins, m.ValueProbs) + + def test_predict_table(self): + learn = SklAdaBoostClassificationLearner() + m = learn(self.iris) + m(self.iris) + _, _ = m(self.iris, m.ValueProbs) + + def test_predict_numpy(self): + learn = SklAdaBoostClassificationLearner() + m = learn(self.iris) + _, _ = m(self.iris.X, m.ValueProbs) + + def test_adaboost_adequacy(self): + learner = SklAdaBoostClassificationLearner() + self.assertRaises(ValueError, learner, self.housing) + + def test_adaboost_reg(self): + learn = SklAdaBoostRegressionLearner() + cv = CrossValidation(k=3) + results = cv(self.housing, [learn]) + _ = RMSE(results) + + def test_adaboost_reg_base_estimator(self): + np.random.seed(0) + stump_estimator = SklTreeRegressionLearner(max_depth=1) + tree_estimator = SklTreeRegressionLearner() + stump = SklAdaBoostRegressionLearner(base_estimator=stump_estimator) + tree = SklAdaBoostRegressionLearner(base_estimator=tree_estimator) + cv = CrossValidation(k=3) + results = cv(self.housing, [stump, tree]) + rmse = RMSE(results) + self.assertGreaterEqual(rmse[0], rmse[1]) + + def test_predict_single_instance_reg(self): + learn = SklAdaBoostRegressionLearner() + m = learn(self.housing) + ins = self.housing[0] + pred = m(ins) + self.assertGreaterEqual(pred, 0) + + def test_predict_table_reg(self): + learn = SklAdaBoostRegressionLearner() + m = learn(self.housing) + pred = m(self.housing) + self.assertEqual(len(self.housing), len(pred)) + self.assertGreater(all(pred), 0) + + def test_predict_numpy_reg(self): + learn = SklAdaBoostRegressionLearner() + m = learn(self.housing) + pred = m(self.housing.X) + self.assertEqual(len(self.housing), len(pred)) + self.assertGreater(all(pred), 0) + + def test_adaboost_adequacy_reg(self): + learner = SklAdaBoostRegressionLearner() + self.assertRaises(ValueError, learner, self.iris) diff --git a/pyminer2/tests/test_base.py b/pyminer2/tests/test_base.py new file mode 100644 index 0000000000000000000000000000000000000000..bb4429f5d79c583b344a1c4944a5872e92fe9f77 --- /dev/null +++ b/pyminer2/tests/test_base.py @@ -0,0 +1,113 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import pickle +import unittest + +from Orange.base import SklLearner, Learner, Model +from Orange.data import Domain +from Orange.preprocess import Discretize, Randomize +from Orange.regression import LinearRegressionLearner + + +class DummyLearner(Learner): + pass + + +class DummyLearnerPP(Learner): + preprocessors = (Randomize(),) + + +class TestLearner(unittest.TestCase): + def test_uses_default_preprocessors_unless_custom_pps_specified(self): + """Learners should use their default preprocessors unless custom + preprocessors were passed in to the constructor""" + learner = DummyLearner() + self.assertEqual( + type(learner).preprocessors, tuple(learner.active_preprocessors), + 'Learner should use default preprocessors, unless preprocessors ' + 'were specified in init') + + def test_overrides_custom_preprocessors(self): + """Passing preprocessors to the learner constructor should override the + default preprocessors defined on the learner""" + pp = Discretize() + learner = DummyLearnerPP(preprocessors=(pp,)) + self.assertEqual( + tuple(learner.active_preprocessors), (pp,), + 'Learner should override default preprocessors when specified in ' + 'constructor') + + def test_use_default_preprocessors_property(self): + """We can specify that we want to use default preprocessors despite + passing our own ones in the constructor""" + learner = DummyLearnerPP(preprocessors=(Discretize(),)) + learner.use_default_preprocessors = True + + preprocessors = list(learner.active_preprocessors) + self.assertEqual( + len(preprocessors), 2, + 'Learner did not properly insert custom preprocessor into ' + 'preprocessor list') + self.assertIsInstance( + preprocessors[0], Discretize, + 'Custom preprocessor was inserted in incorrect order') + self.assertIsInstance(preprocessors[1], Randomize) + + def test_preprocessors_can_be_passed_in_as_non_iterable(self): + """For convenience, we can pass a single preprocessor instance""" + pp = Discretize() + learner = DummyLearnerPP(preprocessors=pp) + self.assertEqual( + tuple(learner.active_preprocessors), (pp,), + 'Preprocessors should be able to be passed in as single object ' + 'as well as an iterable object') + + def test_preprocessors_can_be_passed_in_as_generator(self): + """Since we support iterables, we should support generators as well""" + pp = (Discretize(),) + learner = DummyLearnerPP(p for p in pp) + self.assertEqual( + tuple(learner.active_preprocessors), pp, + 'Preprocessors should be able to be passed in as single object ' + 'as well as an iterable object') + + +class TestSklLearner(unittest.TestCase): + def test_sklearn_supports_weights(self): + """Check that the SklLearner correctly infers whether or not the + learner supports weights""" + + class DummySklLearner: + def fit(self, X, y, sample_weight=None): + pass + + class DummyLearner(SklLearner): + __wraps__ = DummySklLearner + + self.assertTrue(DummyLearner().supports_weights) + + class DummySklLearner: + def fit(self, X, y): + pass + + class DummyLearner(SklLearner): + __wraps__ = DummySklLearner + + self.assertFalse(DummyLearner().supports_weights) + + def test_linreg(self): + self.assertTrue( + LinearRegressionLearner().supports_weights, + "Either LinearRegression no longer supports weighted tables or " + "SklLearner.supports_weights is out-of-date.") + + +class TestModel(unittest.TestCase): + def test_pickle(self): + """Make sure data is not saved when pickling a model.""" + model = Model(Domain([])) + model.original_data = [1, 2, 3] + model2 = pickle.loads(pickle.dumps(model)) + self.assertEqual(model.domain, model2.domain) + self.assertEqual(model.original_data, [1, 2, 3]) + self.assertEqual(model2.original_data, None) diff --git a/pyminer2/tests/test_basic_stats.py b/pyminer2/tests/test_basic_stats.py new file mode 100644 index 0000000000000000000000000000000000000000..3b5ec18792fb67dcbe1e2a2e5dd6d9916bc4c00e --- /dev/null +++ b/pyminer2/tests/test_basic_stats.py @@ -0,0 +1,48 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +from unittest import TestCase + +import time + +import numpy as np + +from Orange.data import Table +from Orange.statistics.basic_stats import DomainBasicStats, BasicStats + + +class TestDomainBasicStats(TestCase): + def setUp(self): + self.zoo = Table("zoo") + + def test_domain_basic_stats(self): + domain = self.zoo.domain + attr_stats = [BasicStats(self.zoo, a) for a in domain.attributes] + class_var_stats = [BasicStats(self.zoo, a) for a in domain.class_vars] + meta_stats = [BasicStats(self.zoo, a) for a in domain.metas] + + domain_stats = DomainBasicStats(self.zoo) + self.assertStatsEqual(domain_stats.stats, + attr_stats + class_var_stats) + + domain_stats = DomainBasicStats(self.zoo, include_metas=True) + self.assertStatsEqual(domain_stats.stats, + attr_stats + class_var_stats + meta_stats) + + def test_speed(self): + n, m = 10, 10000 + data = Table.from_numpy(None, np.random.rand(n, m)) + start = time.time() + for i in range(m): + BasicStats(data, i) + elapsed = time.time() - start + self.assertLess(elapsed, 10.0) + + def assertStatsEqual(self, stats1, stats2): + self.assertEqual(len(stats1), len(stats2)) + for stat1, stat2 in zip(stats1, stats2): + self.assertAlmostEqual(stat1.min, stat2.min) + self.assertAlmostEqual(stat1.max, stat2.max) + self.assertAlmostEqual(stat1.mean, stat2.mean) + self.assertAlmostEqual(stat1.var, stat2.var) + self.assertAlmostEqual(stat1.nans, stat2.nans) + self.assertAlmostEqual(stat1.non_nans, stat2.non_nans) diff --git a/pyminer2/tests/test_basket_reader.py b/pyminer2/tests/test_basket_reader.py new file mode 100644 index 0000000000000000000000000000000000000000..31fedae1b9c673b41ef5deb446b4fc3bf884cd31 --- /dev/null +++ b/pyminer2/tests/test_basket_reader.py @@ -0,0 +1,97 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import functools +import os +import tempfile +import unittest + +import numpy as np + +from Orange.data.io import BasketReader + + +def with_file(s): + def fle_decorator(f, s=s): + @functools.wraps(f) + def decorated(self, s=s): + fle = tempfile.NamedTemporaryFile(delete=False) + fle.write(s.encode("utf-8")) + fle.close() + fname = fle.name + try: + return f(self, fname) + finally: + os.remove(fname) + return decorated + return fle_decorator + + +def read_basket(filename): + return BasketReader(filename).read() + + +class TestBasketReader(unittest.TestCase): + @with_file("""a=1,b=2,c=3""") + def test_read_variable_is_value_syntax(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 3) + self.assertEqual(["a", "b", "c"], + list(map(lambda x: x.name, table.domain.variables))) + np.testing.assert_almost_equal(table.X.todense(), + np.array([[1, 2, 3]])) + + @with_file("""a,b,c,d,e""") + def test_read_variable_only_syntax(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 5) + np.testing.assert_almost_equal(table.X.todense(), + np.array([[1, 1, 1, 1, 1]])) + + @with_file("""a=1, b=2, c=3""") + def test_handles_spaces_between_variables(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 3) + self.assertEqual(set(x for x in table[0]), {1, 2, 3}) + + @with_file("""a=1, b=2\na=1, b=4""") + def test_variables_can_be_listed_in_any_order(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 2) + np.testing.assert_almost_equal(table.X.todense(), + np.array([[1, 2], [1, 4]])) + + + @with_file("""a,b\nc,b,a""") + def test_variables_can_be_listed_in_any_order(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 3) + np.testing.assert_almost_equal(table.X.todense(), + np.array([[1, 1, 0], [1, 1, 1]])) + + @with_file("""č,š,ž""") + def test_handles_unicode(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 3) + np.testing.assert_almost_equal(table.X.todense(), + np.array([[1, 1, 1]])) + + @with_file("""a=4,"x"=1.0,"y"=2.0,b=5\n"x"=1.0""") + def test_handles_quote(self, fname): + table = read_basket(fname) + self.assertEqual(len(table.domain.variables), 4) + + @with_file("""a,a,b\nb=2,b=3,c""") + def test_sums_duplicates(self, fname): + table = read_basket(fname) + np.testing.assert_array_equal(table.X.toarray(), [[2, 1, 0.], + [0, 5, 1]]) + + def test_data_name(self): + filename = os.path.join(os.path.dirname(__file__), + 'datasets/iris_basket.basket') + self.assertEqual(read_basket(filename).name, 'iris_basket') + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_classification.py b/pyminer2/tests/test_classification.py new file mode 100644 index 0000000000000000000000000000000000000000..d186cea67c8354e6b512df522a2a78528fe5eb8b --- /dev/null +++ b/pyminer2/tests/test_classification.py @@ -0,0 +1,411 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import inspect +import pickle +import pkgutil +import unittest + +import traceback +import warnings + +import numpy as np +from scipy import sparse as sp +from sklearn.exceptions import ConvergenceWarning + +from Orange.base import SklLearner + +import Orange.classification +from Orange.classification import ( + Learner, Model, + NaiveBayesLearner, LogisticRegressionLearner, NuSVMLearner, MajorityLearner, + RandomForestLearner, SimpleTreeLearner, SoftmaxRegressionLearner, + SVMLearner, LinearSVMLearner, OneClassSVMLearner, TreeLearner, KNNLearner, + SimpleRandomForestLearner, EllipticEnvelopeLearner) +from Orange.classification.rules import _RuleLearner +from Orange.data import (ContinuousVariable, DiscreteVariable, + Domain, Table, Variable) +from Orange.data.table import DomainTransformationError +from Orange.evaluation import CrossValidation +from Orange.tests.dummy_learners import DummyLearner, DummyMulticlassLearner +from Orange.tests import test_filename + + +class MultiClassTest(unittest.TestCase): + def test_unsupported(self): + nrows = 20 + ncols = 10 + x = np.random.randint(1, 4, (nrows, ncols)) + + # multiple class variables + y = np.random.randint(0, 2, (nrows, 2)) + t = Table.from_numpy(None, x, y) + learn = DummyLearner() + # TODO: Errors raised from various data checks should be made consistent + with self.assertRaises((ValueError, TypeError)): + clf = learn(t) + + # single class variable + y = np.random.randint(0, 2, (nrows, 1)) + t = Table.from_numpy(None, x, y) + learn = DummyLearner() + clf = learn(t) + z = clf(x) + self.assertEqual(z.ndim, 1) + + def test_supported(self): + nrows = 20 + ncols = 10 + x = np.random.randint(1, 4, (nrows, ncols)) + y = np.random.randint(0, 2, (nrows, 2)) + t = Table.from_numpy(None, x, y) + learn = DummyMulticlassLearner() + clf = learn(t) + z = clf(x) + self.assertEqual(z.shape, y.shape) + + +class ModelTest(unittest.TestCase): + def test_predict_single_instance(self): + table = Table("titanic") + learn = NaiveBayesLearner() + clf = learn(table) + pred = [] + for row in table: + pred.append(clf(row)) + + def test_prediction_dimensions(self): + class MockModel(Model): + def predict(self, data): + return np.zeros((data.shape[0], len(domain.class_var.values))) + + x = np.zeros((42, 5)) + y = np.zeros(42) + domain = Domain([ContinuousVariable(n) for n in "abcde"], + DiscreteVariable("y", values=["a", "b"])) + data = Table.from_numpy(domain, x, y) + a_list = [[0] * 5] * 42 + a_tuple = ((0, ) * 5,) * 42 + m = MockModel(domain) + + for inp in (data, x, sp.csr_matrix(x), a_list, a_tuple): + msg = f"in test for type '{type(inp)}'" + # two-dimensional + self.assertEqual(m(inp, ret=m.Value).shape, (42, ), msg) + self.assertEqual(m(inp, ret=m.Probs).shape, (42, 2), msg) + values, probs = m(inp, ret=m.ValueProbs) + self.assertEqual(values.shape, (42, ), msg) + self.assertEqual(probs.shape, (42, 2), msg) + + # one-dimensional + if not isinstance(inp, sp.csr_matrix): + self.assertEqual(m(inp[0], ret=m.Value).shape, (), msg) + self.assertEqual(m(inp[0], ret=m.Probs).shape, (2, ), msg) + values, probs = m(inp[0], ret=m.ValueProbs) + self.assertEqual(values.shape, (), msg) + self.assertEqual(probs.shape, (2, ), msg) + + def test_learner_adequacy(self): + table = Table("housing") + learner = NaiveBayesLearner() + self.assertRaises(ValueError, learner, table) + + def test_value_from_probs(self): + nrows = 100 + ncols = 5 + x = np.random.randint(0, 2, (nrows, ncols)) + + # single class variable + y = np.random.randint(1, 4, (nrows, 1)) // 2 # majority = 1 + t = Table.from_numpy(None, x, y) + learn = DummyLearner() + clf = learn(t) + clf.ret = Model.Probs + y2 = clf(x, ret=Model.Value) + self.assertEqual(y2.shape, (nrows,)) + y2, probs = clf(x, ret=Model.ValueProbs) + self.assertEqual(y2.shape, (nrows,)) + self.assertEqual(probs.shape, (nrows, 2)) + + # multitarget + y = np.random.randint(1, 6, (nrows, 2)) + y[:, 0] = y[:, 0] // 3 # majority = 1 + y[:, 1] = (y[:, 1] + 4) // 3 # majority = 2 + domain = Domain([ContinuousVariable('i' + str(i)) for i in range(ncols)], + [DiscreteVariable('c' + str(i), values="0123") + for i in range(y.shape[1])]) + t = Table(domain, x, y) + learn = DummyMulticlassLearner() + clf = learn(t) + clf.ret = Model.Probs + y2 = clf(x, ret=Model.Value) + self.assertEqual(y2.shape, y.shape) + y2, probs = clf(x, ret=Model.ValueProbs) + self.assertEqual(y2.shape, y.shape) + self.assertEqual(probs.shape, (nrows, 2, 4)) + + def test_probs_from_value(self): + nrows = 100 + ncols = 5 + x = np.random.randint(0, 2, (nrows, ncols)) + + # single class variable + y = np.random.randint(0, 2, (nrows, 1)) + d = Domain([DiscreteVariable('v' + str(i), + values=[str(v) + for v in np.unique(x[:, i])]) + for i in range(ncols)], + DiscreteVariable('c', values="12")) + t = Table(d, x, y) + learn = DummyLearner() + clf = learn(t) + clf.ret = Model.Value + y2 = clf(x, ret=Model.Probs) + self.assertEqual(y2.shape, (nrows, 2)) + y2, probs = clf(x, ret=Model.ValueProbs) + self.assertEqual(y2.shape, (nrows, )) + self.assertEqual(probs.shape, (nrows, 2)) + + # multitarget + y = np.random.randint(1, 6, (nrows, 2)) + y[:, 0] = y[:, 0] // 3 # majority = 1 + y[:, 1] = (y[:, 1] + 4) // 3 - 1 # majority = 1 + domain = Domain([ContinuousVariable('i' + str(i)) for i in range(ncols)], + [DiscreteVariable('c' + str(i), values="0123") + for i in range(y.shape[1])]) + t = Table(domain, x, y) + learn = DummyMulticlassLearner() + clf = learn(t) + clf.ret = Model.Value + probs = clf(x, ret=Model.Probs) + self.assertEqual(probs.shape, (nrows, 2, 4)) + y2, probs = clf(x, ret=Model.ValueProbs) + self.assertEqual(y2.shape, y.shape) + self.assertEqual(probs.shape, (nrows, 2, 4)) + + def test_incompatible_domain(self): + iris = Table("iris") + titanic = Table("titanic") + clf = DummyLearner()(iris) + with self.assertRaises(DomainTransformationError): + clf(titanic) + + +class ExpandProbabilitiesTest(unittest.TestCase): + def prepareTable(self, rows, attr, vars, class_var_domain): + attributes = ["Feature %i" % i for i in range(attr)] + classes = ["Class %i" % i for i in range(vars)] + attr_vars = [DiscreteVariable(name=a, values="01") for a in attributes] + class_vars = [ + DiscreteVariable(name=c, + values=[str(v) for v in range(class_var_domain)]) + for c in classes] + meta_vars = [] + self.domain = Domain(attr_vars, class_vars, meta_vars) + self.x = np.random.randint(0, 2, (rows, attr)) + + def test_single_class(self): + rows = 10 + attr = 3 + vars = 1 + class_var_domain = 20 + self.prepareTable(rows, attr, vars, class_var_domain) + y = np.random.randint(2, 6, (rows, vars)) * 2 + t = Table(self.domain, self.x, y) + learn = DummyLearner() + clf = learn(t) + z, p = clf(self.x, ret=Model.ValueProbs) + self.assertEqual(p.shape, (rows, class_var_domain)) + self.assertTrue(np.all(z == np.argmax(p, axis=-1))) + + def test_multi_class(self): + rows = 10 + attr = 3 + vars = 5 + class_var_domain = 20 + self.prepareTable(rows, attr, vars, class_var_domain) + y = np.random.randint(2, 6, (rows, vars)) * 2 + t = Table(self.domain, self.x, y) + learn = DummyMulticlassLearner() + clf = learn(t) + z, p = clf(self.x, ret=Model.ValueProbs) + self.assertEqual(p.shape, (rows, vars, class_var_domain)) + self.assertTrue(np.all(z == np.argmax(p, axis=-1))) + + +class SklTest(unittest.TestCase): + def test_multinomial(self): + table = Table("titanic") + lr = LogisticRegressionLearner() + assert isinstance(lr, Orange.classification.SklLearner) + cv = CrossValidation(k=2) + res = cv(table, [lr]) + self.assertGreater(Orange.evaluation.AUC(res)[0], 0.7) + self.assertLess(Orange.evaluation.AUC(res)[0], 0.9) + + def test_nan_columns(self): + data = Orange.data.Table("iris") + data.X[:, (1, 3)] = np.NaN + lr = LogisticRegressionLearner() + cv = CrossValidation(k=2, store_models=True) + res = cv(data, [lr]) + self.assertEqual(len(res.models[0][0].domain.attributes), 2) + self.assertGreater(Orange.evaluation.CA(res)[0], 0.8) + + def test_params(self): + learner = SklLearner() + self.assertIsInstance(learner.params, dict) + + +class ClassfierListInputTest(unittest.TestCase): + def test_discrete(self): + table = Table("titanic") + tree = Orange.classification.SklTreeLearner()(table) + strlist = [["crew", "adult", "male"], + ["crew", "adult", None]] + for se in strlist: #individual examples + assert(all(tree(se) == + tree(Orange.data.Table.from_list(table.domain, [se])))) + assert(all(tree(strlist) == + tree(Orange.data.Table.from_list(table.domain, strlist)))) + + def test_continuous(self): + table = Table("iris") + tree = Orange.classification.SklTreeLearner()(table) + strlist = [[2, 3, 4, 5], + [1, 2, 3, 5]] + for se in strlist: #individual examples + assert(all(tree(se) == + tree(Orange.data.Table.from_list(table.domain, [se])))) + assert(all(tree(strlist) == + tree(Orange.data.Table.from_list(table.domain, strlist)))) + + +class UnknownValuesInPrediction(unittest.TestCase): + def test_unknown(self): + table = Table("iris") + tree = LogisticRegressionLearner()(table) + tree([1, 2, None]) + + def test_missing_class(self): + table = Table(test_filename("datasets/adult_sample_missing")) + for learner in LearnerAccessibility().all_learners(): + try: + learner = learner() + if isinstance(learner, NuSVMLearner): + learner.params["nu"] = 0.01 + # Skip slow tests + if isinstance(learner, _RuleLearner): + continue + model = learner(table) + model(table) + except TypeError: + traceback.print_exc() + continue + + +class LearnerAccessibility(unittest.TestCase): + + def setUp(self): + # Convergence warnings are irrelevant for these tests + warnings.filterwarnings("ignore", ".*", ConvergenceWarning) + + + def all_learners(self): + classification_modules = pkgutil.walk_packages( + path=Orange.classification.__path__, + prefix="Orange.classification.", + onerror=lambda x: None) + for importer, modname, ispkg in classification_modules: + try: + module = pkgutil.importlib.import_module(modname) + except ImportError: + continue + + for name, class_ in inspect.getmembers(module, inspect.isclass): + if (issubclass(class_, Learner) and + not name.startswith('_') and + 'base' not in class_.__module__): + yield class_ + + def test_all_learners_accessible_in_Orange_classification_namespace(self): + for learner in self.all_learners(): + if not hasattr(Orange.classification, learner.__name__): + self.fail("%s is not visible in Orange.classification" + " namespace" % learner.__name__) + + def test_all_models_work_after_unpickling(self): + datasets = [Table('iris'), Table('titanic')] + for learner in list(self.all_learners()): + try: + learner = learner() + except Exception: + print('%s cannot be used with default parameters' % learner.__name__) + traceback.print_exc() + continue + # Skip slow tests + if isinstance(learner, _RuleLearner): + continue + + for ds in datasets: + model = learner(ds) + s = pickle.dumps(model, 0) + model2 = pickle.loads(s) + + np.testing.assert_almost_equal( + Table.from_table(model.domain, ds).X, + Table.from_table(model2.domain, ds).X) + np.testing.assert_almost_equal( + model(ds), model2(ds), + err_msg='%s does not return same values when unpickled %s' + % (learner.__class__.__name__, ds.name)) + + def test_adequacy_all_learners(self): + for learner in self.all_learners(): + try: + learner = learner() + table = Table("housing") + self.assertRaises(ValueError, learner, table) + except TypeError: + traceback.print_exc() + continue + + def test_adequacy_all_learners_multiclass(self): + for learner in self.all_learners(): + try: + learner = learner() + table = Table(test_filename("datasets/test8.tab")) + self.assertRaises(ValueError, learner, table) + except TypeError: + traceback.print_exc() + continue + + +class LearnerReprs(unittest.TestCase): + def test_reprs(self): + lr = LogisticRegressionLearner(tol=0.0002) + m = MajorityLearner() + nb = NaiveBayesLearner() + rf = RandomForestLearner(bootstrap=False, n_jobs=3) + st = SimpleTreeLearner(seed=1, bootstrap=True) + sm = SoftmaxRegressionLearner() + svm = SVMLearner(shrinking=False) + lsvm = LinearSVMLearner(tol=0.022, dual=False) + nsvm = NuSVMLearner(tol=0.003, cache_size=190) + osvm = OneClassSVMLearner(degree=2) + tl = TreeLearner(max_depth=3, min_samples_split=1) + knn = KNNLearner(n_neighbors=4) + el = EllipticEnvelopeLearner(store_precision=False) + srf = SimpleRandomForestLearner(n_estimators=20) + + learners = [lr, m, nb, rf, st, sm, svm, + lsvm, nsvm, osvm, tl, knn, el, srf] + + for l in learners: + repr_str = repr(l) + new_l = eval(repr_str) + self.assertEqual(repr(new_l), repr_str) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_clustering_dbscan.py b/pyminer2/tests/test_clustering_dbscan.py new file mode 100644 index 0000000000000000000000000000000000000000..3286f5a714dcf376bfe7489c5be254cbcea52903 --- /dev/null +++ b/pyminer2/tests/test_clustering_dbscan.py @@ -0,0 +1,96 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +from scipy.sparse import csc_matrix, csr_matrix + +from Orange.clustering.clustering import ClusteringModel +from Orange.data import Table +from Orange.clustering.dbscan import DBSCAN + + +class TestDBSCAN(unittest.TestCase): + def setUp(self): + self.iris = Table('iris') + self.dbscan = DBSCAN() + + def test_dbscan(self): + c = self.dbscan(self.iris) + # First 20 iris belong to one cluster + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + self.assertEqual(1, len(set(c[:20].ravel()))) + + def test_dbscan_parameters(self): + dbscan = DBSCAN(eps=0.1, min_samples=7, metric='euclidean', + algorithm='auto', leaf_size=12, p=None) + c = dbscan(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_table(self): + pred = self.dbscan(self.iris) + self.assertEqual(np.ndarray, type(pred)) + self.assertEqual(len(self.iris), len(pred)) + + def test_predict_numpy(self): + model = self.dbscan.fit(self.iris.X) + self.assertEqual(ClusteringModel, type(model)) + self.assertEqual(np.ndarray, type(model.labels)) + self.assertEqual(len(self.iris), len(model.labels)) + + def test_predict_sparse_csc(self): + self.iris.X = csc_matrix(self.iris.X[::20]) + c = self.dbscan(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_spares_csr(self): + self.iris.X = csr_matrix(self.iris.X[::20]) + c = self.dbscan(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_model(self): + c = self.dbscan.get_model(self.iris) + self.assertEqual(ClusteringModel, type(c)) + self.assertEqual(len(self.iris), len(c.labels)) + + self.assertRaises(NotImplementedError, c, self.iris) + + def test_model_np(self): + """ + Test with numpy array as an input in model. + """ + c = self.dbscan.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris.X) + + def test_model_sparse(self): + """ + Test with sparse array as an input in model. + """ + c = self.dbscan.get_model(self.iris) + self.assertRaises(NotImplementedError, c, csr_matrix(self.iris.X)) + + def test_model_instance(self): + """ + Test with instance as an input in model. + """ + c = self.dbscan.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris[0]) + + def test_model_list(self): + """ + Test with list as an input in model. + """ + c = self.dbscan.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris.X.tolist()) + + def test_model_bad_datatype(self): + """ + Check model with data-type that is not supported. + """ + c = self.dbscan.get_model(self.iris) + self.assertRaises(TypeError, c, 10) diff --git a/pyminer2/tests/test_clustering_hierarchical.py b/pyminer2/tests/test_clustering_hierarchical.py new file mode 100644 index 0000000000000000000000000000000000000000..9435a128c0dedb059dde23cdd184216cd734c857 --- /dev/null +++ b/pyminer2/tests/test_clustering_hierarchical.py @@ -0,0 +1,218 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +from numpy.testing import assert_array_equal + +import unittest +from itertools import chain, tee + +import numpy + +from Orange.clustering import hierarchical +import Orange.misc + + +def flatten(seq): + return chain(*seq) + + +class TestHierarchical(unittest.TestCase): + @classmethod + def setUpClass(cls): + m = [[], + [3], + [2, 4], + [17, 5, 4], + [2, 8, 3, 8], + [7, 5, 10, 11, 2], + [8, 4, 1, 5, 11, 13], + [4, 7, 12, 8, 10, 1, 5], + [13, 9, 14, 15, 7, 8, 4, 6], + [12, 10, 11, 15, 2, 5, 7, 3, 1]] + cls.items = ["Ann", "Bob", "Curt", "Danny", "Eve", "Fred", + "Greg", "Hue", "Ivy", "Jon"] + + dist = numpy.array(list(flatten(m)), dtype=float) + matrix = hierarchical.squareform(dist, mode="lower") + cls.m = m + cls.matrix = Orange.misc.DistMatrix(matrix) + cls.matrix.items = cls.items + + cls.cluster = hierarchical.dist_matrix_clustering(cls.matrix) + + def test_mapping(self): + leaves = list(hierarchical.leaves(self.cluster)) + indices = [n.value.index for n in leaves] + + self.assertEqual(len(indices), len(self.matrix.items)) + self.assertEqual(set(indices), set(range(len(self.matrix.items)))) + + #self.assertEqual(indices, + # [3, 1, 2, 6, 0, 4, 8, 9, 5, 7]) + + def test_order(self): + post = list(hierarchical.postorder(self.cluster)) + seen = set() + + for n in post: + self.assertTrue(all(ch in seen for ch in n.branches)) + seen.add(n) + + pre = list(hierarchical.preorder(self.cluster)) + seen = set() + for n in pre: + self.assertTrue(all(ch not in seen for ch in n.branches)) + seen.add(n) + + def test_prunning(self): + pruned = hierarchical.prune(self.cluster, level=2) + depths = hierarchical.cluster_depths(pruned) + self.assertTrue(all(d <= 2 for d in depths.values())) + + pruned = hierarchical.prune(self.cluster, height=10) + self.assertTrue(c.height >= 10 for c in hierarchical.preorder(pruned)) + + top = hierarchical.top_clusters(self.cluster, 3) + self.assertEqual(len(top), 3) + + top = hierarchical.top_clusters(self.cluster, len(self.matrix)) + self.assertEqual(len(top), len(self.matrix)) + self.assertTrue(all(n.is_leaf for n in top)) + + top1 = hierarchical.top_clusters(self.cluster, len(self.matrix) + 1) + self.assertEqual(top1, top) + + def test_form(self): + m = [[0, 2, 3, 4], + [2, 0, 6, 7], + [3, 6, 0, 8], + [4, 7, 8, 0]] + + m = numpy.array(m) + dist = hierarchical.condensedform(m, mode="lower") + numpy.testing.assert_equal(dist, numpy.array([2, 3, 6, 4, 7, 8])) + numpy.testing.assert_equal( + hierarchical.squareform(dist, mode="lower"), m) + dist = hierarchical.condensedform(m, mode="upper") + numpy.testing.assert_equal(dist, numpy.array([2, 3, 4, 6, 7, 8])) + numpy.testing.assert_equal( + hierarchical.squareform(dist, mode="upper"), m) + + def test_pre_post_order(self): + tree = hierarchical.Tree + root = tree("A", (tree("B"), tree("C"))) + self.assertEqual([n.value for n in hierarchical.postorder(root)], + ["B", "C", "A"]) + self.assertEqual([n.value for n in hierarchical.preorder(root)], + ["A", "B", "C"]) + + def test_optimal_ordering(self): + def indices(root): + return [leaf.value.index for leaf in hierarchical.leaves(root)] + + ordered = hierarchical.optimal_leaf_ordering( + self.cluster, self.matrix) + + self.assertEqual(ordered.value.range, self.cluster.value.range) + self.assertSetEqual(set(indices(self.cluster)), + set(indices(ordered))) + + def pairs(iterable): + i1, i2 = tee(iterable) + next(i1) + yield from zip(i1, i2) + + def score(root): + return sum([self.matrix[i, j] for i, j in pairs(indices(root))]) + score_unordered = score(self.cluster) + score_ordered = score(ordered) + self.assertGreater(score_unordered, score_ordered) + self.assertEqual(score_ordered, 21.0) + + def test_table_clustering(self): + table = Orange.data.Table.from_numpy(None, numpy.eye(3)) + tree = hierarchical.data_clustering(table, linkage="single") + numpy.testing.assert_almost_equal(tree.value.height, numpy.sqrt(2)) + + tree = hierarchical.feature_clustering(table) + numpy.testing.assert_almost_equal(tree.value.height, 0.75) + + def test_invalid_linkage(self): + link = numpy.array( + [[0.0, 1.0, 1.0, 2.0], + [2.0, 1.0, 2.0, 3.0]] + ) + with self.assertRaises(ValueError): + hierarchical.tree_from_linkage(link) + + def test_linkage_from_tree(self): + T = hierarchical.Tree + C = hierarchical.ClusterData + S = hierarchical.SingletonData + + def t(h: float, left: T, right: T): + return T(C((left.value.first, right.value.last), h), (left, right)) + + def leaf(r, index): + return T(S((r, r + 1), 0.0, index)) + + assert_array_equal( + hierarchical.linkage_from_tree(leaf(0, 0)), + numpy.empty((0, 4)) + ) + assert_array_equal( + hierarchical.linkage_from_tree(t(1.0, leaf(0, 0), leaf(1, 1))), + numpy.array([ + [0, 1, 1.0, 0.0] + ]) + ) + + tree = t(1.0, t(0.2, leaf(0, 0), leaf(1, 1)), leaf(2, 2)) + Z = hierarchical.linkage_from_tree(tree) + assert_array_equal( + Z, + numpy.array([ + [0, 1, 0.2, 0.0], + [3, 2, 1.0, 0.0] + ]) + ) + self.assertEqual(tree, hierarchical.tree_from_linkage(Z)) + + tree = t( + 2.0, + left=t(0.5, leaf(0, 1), leaf(1, 2)), + right=t(1.0, leaf(2, 0), leaf(3, 3),) + ) + + Z = hierarchical.linkage_from_tree(tree) + assert_array_equal( + Z, + numpy.array([ + [1, 2, 0.5, 0.0], + [0, 3, 1.0, 0.0], + [4, 5, 2.0, 0.0] + ]) + ) + self.assertEqual(tree, hierarchical.tree_from_linkage(Z)) + + +class TestTree(unittest.TestCase): + def test_tree(self): + Tree = hierarchical.Tree + + left = Tree(0, ()) + self.assertTrue(left.is_leaf) + right = Tree(1, ()) + self.assertEqual(left, Tree(0, ())) + self.assertNotEqual(left, right) + self.assertLess(left, right) + + root = Tree(2, (left, right)) + self.assertFalse(root.is_leaf) + self.assertIs(root.left, left) + self.assertIs(root.right, right) + + val, br = root + + self.assertEqual(val, 2) + self.assertEqual(br, (left, right)) + self.assertEqual(repr(left), "Tree(value=0, branches=())") diff --git a/pyminer2/tests/test_clustering_kmeans.py b/pyminer2/tests/test_clustering_kmeans.py new file mode 100644 index 0000000000000000000000000000000000000000..7ff40d9499264a118e2b52ba9eb7f8569c7d4b43 --- /dev/null +++ b/pyminer2/tests/test_clustering_kmeans.py @@ -0,0 +1,150 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import warnings + +import numpy as np +from scipy.sparse import csc_matrix, csr_matrix + +import Orange +from Orange.clustering.kmeans import KMeans, KMeansModel +from Orange.data import Table, Domain, ContinuousVariable +from Orange.data.table import DomainTransformationError + + +class TestKMeans(unittest.TestCase): + def setUp(self): + self.kmeans = KMeans(n_clusters=2) + self.iris = Orange.data.Table('iris') + + def test_kmeans(self): + c = self.kmeans(self.iris) + # First 20 iris belong to one cluster + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + self.assertEqual(1, len(set(c[:20].ravel()))) + + def test_kmeans_parameters(self): + kmeans = KMeans(n_clusters=10, max_iter=10, random_state=42, tol=0.001, + init='random') + c = kmeans(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_table(self): + c = self.kmeans(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_numpy(self): + c = self.kmeans.fit(self.iris.X) + self.assertEqual(KMeansModel, type(c)) + self.assertEqual(np.ndarray, type(c.labels)) + self.assertEqual(len(self.iris), len(c.labels)) + + def test_predict_sparse_csc(self): + self.iris.X = csc_matrix(self.iris.X[::20]) + c = self.kmeans(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_spares_csr(self): + self.iris.X = csr_matrix(self.iris.X[::20]) + c = self.kmeans(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_model(self): + c = self.kmeans.get_model(self.iris) + self.assertEqual(KMeansModel, type(c)) + self.assertEqual(len(self.iris), len(c.labels)) + + c1 = c(self.iris) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels, c1) + + def test_model_np(self): + """ + Test with numpy array as an input in model. + """ + c = self.kmeans.get_model(self.iris) + c1 = c(self.iris.X) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels, c1) + + def test_model_sparse_csc(self): + """ + Test with sparse array as an input in model. + """ + c = self.kmeans.get_model(self.iris) + c1 = c(csc_matrix(self.iris.X)) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels, c1) + + def test_model_sparse_csr(self): + """ + Test with sparse array as an input in model. + """ + c = self.kmeans.get_model(self.iris) + c1 = c(csr_matrix(self.iris.X)) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels, c1) + + def test_model_instance(self): + """ + Test with instance as an input in model. + """ + c = self.kmeans.get_model(self.iris) + c1 = c(self.iris[0]) + # prediction of the model must be same since data are same + self.assertEqual(c1, c.labels[0]) + + def test_model_list(self): + """ + Test with list as an input in model. + """ + c = self.kmeans.get_model(self.iris) + c1 = c(self.iris.X.tolist()) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels, c1) + + # example with a list of only one data item + c1 = c(self.iris.X.tolist()[0]) + # prediction of the model must be same since data are same + np.testing.assert_array_almost_equal(c.labels[0], c1) + + def test_model_bad_datatype(self): + """ + Check model with data-type that is not supported. + """ + c = self.kmeans.get_model(self.iris) + self.assertRaises(TypeError, c, 10) + + def test_model_data_table_domain(self): + """ + Check model with data-type that is not supported. + """ + # ok domain + data = Table(Domain( + list(self.iris.domain.attributes) + [ContinuousVariable("a")]), + np.concatenate((self.iris.X, np.ones((len(self.iris), 1))), axis=1)) + c = self.kmeans.get_model(self.iris) + res = c(data) + np.testing.assert_array_almost_equal(c.labels, res) + + # totally different domain - should fail + self.assertRaises(DomainTransformationError, c, Table("housing")) + + def test_deprecated_silhouette(self): + with warnings.catch_warnings(record=True) as w: + KMeans(compute_silhouette_score=True) + + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + + with warnings.catch_warnings(record=True) as w: + KMeans(compute_silhouette_score=False) + + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) diff --git a/pyminer2/tests/test_clustering_louvain.py b/pyminer2/tests/test_clustering_louvain.py new file mode 100644 index 0000000000000000000000000000000000000000..a65ba4a8edf6a4418bb2d59d713be4f458d399a0 --- /dev/null +++ b/pyminer2/tests/test_clustering_louvain.py @@ -0,0 +1,120 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +import networkx +from scipy.sparse import csc_matrix, csr_matrix + +from Orange.clustering.clustering import ClusteringModel +from Orange.clustering.louvain import matrix_to_knn_graph +from Orange.data import Table +from Orange.clustering.louvain import Louvain + + +class TestLouvain(unittest.TestCase): + def setUp(self): + self.iris = Table('iris') + self.louvain = Louvain() + + def test_louvain(self): + c = self.louvain(self.iris) + # First 20 iris belong to one cluster + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + self.assertEqual(1, len(set(c[:20].ravel()))) + + def test_louvain_parameters(self): + louvain = Louvain( + k_neighbors=3, resolution=1.2, random_state=42, metric="l2") + c = louvain(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_table(self): + c = self.louvain(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_numpy(self): + c = self.louvain.fit(self.iris.X) + self.assertEqual(ClusteringModel, type(c)) + self.assertEqual(np.ndarray, type(c.labels)) + self.assertEqual(len(self.iris), len(c.labels)) + + def test_predict_sparse_csc(self): + self.iris.X = csc_matrix(self.iris.X[::5]) + c = self.louvain(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_predict_spares_csr(self): + self.iris.X = csr_matrix(self.iris.X[::5]) + c = self.louvain(self.iris) + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + + def test_model(self): + c = self.louvain.get_model(self.iris) + self.assertEqual(ClusteringModel, type(c)) + self.assertEqual(len(self.iris), len(c.labels)) + + self.assertRaises(NotImplementedError, c, self.iris) + + def test_model_np(self): + """ + Test with numpy array as an input in model. + """ + c = self.louvain.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris.X) + + def test_model_sparse(self): + """ + Test with sparse array as an input in model. + """ + c = self.louvain.get_model(self.iris) + self.assertRaises(NotImplementedError, c, csr_matrix(self.iris.X)) + + def test_model_instance(self): + """ + Test with instance as an input in model. + """ + c = self.louvain.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris[0]) + + def test_model_list(self): + """ + Test with list as an input in model. + """ + c = self.louvain.get_model(self.iris) + self.assertRaises(NotImplementedError, c, self.iris.X.tolist()) + + def test_graph(self): + """ + Louvain accepts graphs too. + :return: + """ + graph = matrix_to_knn_graph(self.iris.X, 30, "l2") + self.assertIsNotNone(graph) + self.assertEqual(networkx.Graph, type(graph), 1) + + # basic clustering - get clusters + c = self.louvain(graph) + # First 20 iris belong to one cluster + self.assertEqual(np.ndarray, type(c)) + self.assertEqual(len(self.iris), len(c)) + self.assertEqual(1, len(set(c[:20].ravel()))) + + # clustering - get model + c = self.louvain.get_model(graph) + # First 20 iris belong to one cluster + self.assertEqual(ClusteringModel, type(c)) + self.assertEqual(len(self.iris), len(c.labels)) + + def test_model_bad_datatype(self): + """ + Check model with data-type that is not supported. + """ + c = self.louvain.get_model(self.iris) + self.assertRaises(TypeError, c, 10) diff --git a/pyminer2/tests/test_contingency.py b/pyminer2/tests/test_contingency.py new file mode 100644 index 0000000000000000000000000000000000000000..022da6d6973518da03f5d991cd5065f8aafd9bb7 --- /dev/null +++ b/pyminer2/tests/test_contingency.py @@ -0,0 +1,393 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import Mock + +import numpy as np +import scipy.sparse as sp +from scipy.sparse import csr_matrix, csc_matrix + +from Orange.data import DiscreteVariable, Table, Domain +from Orange.statistics import contingency +from Orange import data +from Orange.tests import test_filename + + +def assert_dist_equal(dist, expected): + np.testing.assert_array_equal(np.asarray(dist), expected) + + +def assert_dist_almost_equal(dist, expected): + np.testing.assert_array_almost_equal(np.asarray(dist), expected) + + +class TestDiscrete(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.zoo = data.Table("zoo") + cls.test9 = data.Table(test_filename("datasets/test9.tab")) + + def test_discrete(self): + cont = contingency.Discrete(self.zoo, 0) + assert_dist_equal(cont["amphibian"], [4, 0]) + assert_dist_equal(cont, [[4, 0], [20, 0], [13, 0], + [4, 4], [10, 0], [2, 39], [5, 0]]) + + cont = contingency.Discrete(self.zoo, "predator") + assert_dist_equal(cont["fish"], [4, 9]) + assert_dist_equal(cont, [[1, 3], [11, 9], [4, 9], [7, 1], + [2, 8], [19, 22], [1, 4]]) + + cont = contingency.Discrete(self.zoo, self.zoo.domain["predator"]) + assert_dist_equal(cont["fish"], [4, 9]) + assert_dist_equal(cont, [[1, 3], [11, 9], [4, 9], [7, 1], + [2, 8], [19, 22], [1, 4]]) + self.assertEqual(sum(cont.col_unknowns), 0) + self.assertEqual(sum(cont.row_unknowns), 0) + + def test_discrete_missing(self): + d = data.Table("zoo") + d.Y[25] = float("nan") + d[0][0] = float("nan") + cont = contingency.Discrete(d, 0) + assert_dist_equal(cont["amphibian"], [3, 0]) + assert_dist_equal(cont, [[3, 0], [20, 0], [13, 0], [4, 4], + [10, 0], [2, 38], [5, 0]]) + np.testing.assert_almost_equal(cont.col_unknowns, + [0, 0, 0, 0, 0, 1, 0]) + np.testing.assert_almost_equal(cont.row_unknowns, + [1, 0]) + + d = data.Table("zoo") + d.Y[2] = float("nan") + d[2]["predator"] = float("nan") + cont = contingency.Discrete(d, "predator") + assert_dist_equal(cont["fish"], [4, 8]) + assert_dist_equal(cont, [[1, 3], [11, 9], [4, 8], [7, 1], + [2, 8], [19, 22], [1, 4]]) + np.testing.assert_almost_equal( + cont.col_unknowns, [0, 0, 0, 0, 0, 0, 0]) + np.testing.assert_almost_equal(cont.row_unknowns, [0, 0]) + self.assertEqual(1, cont.unknowns) + + def test_array_with_unknowns(self): + d = data.Table("zoo") + d.Y[2] = float("nan") + d.Y[6] = float("nan") + d[2]["predator"] = float("nan") + d[4]["predator"] = float("nan") + cont = contingency.Discrete(d, "predator") + assert_dist_equal(cont.array_with_unknowns, + [[1, 3, 0], [11, 9, 0], [4, 8, 0], [7, 1, 0], + [2, 8, 0], [18, 21, 1], [1, 4, 0], [1, 0, 1]]) + + def test_discrete_with_fallback(self): + d = data.Table("zoo") + d.Y[25] = None + d.Y[24] = None + d.X[0, 0] = None + d.X[24, 0] = None + default = contingency.Discrete(d, 0) + + d._compute_contingency = Mock(side_effect=NotImplementedError) + fallback = contingency.Discrete(d, 0) + + np.testing.assert_array_equal( + np.asarray(fallback), np.asarray(default)) + np.testing.assert_array_equal(fallback.unknowns, default.unknowns) + np.testing.assert_array_equal( + fallback.row_unknowns, default.row_unknowns) + np.testing.assert_array_equal( + fallback.col_unknowns, default.col_unknowns) + + def test_continuous(self): + d = data.Table("iris") + cont = contingency.Continuous(d, "sepal width") + correct = [[2.3, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, + 3.8, 3.9, 4.0, 4.1, 4.2, 4.4], + [1, 1, 6, 5, 5, 2, 9, 6, 2, 3, 4, 2, 1, 1, 1, 1]] + + np.testing.assert_almost_equal(cont.col_unknowns, [0, 0, 0]) + np.testing.assert_almost_equal(cont.row_unknowns, np.zeros(23)) + np.testing.assert_almost_equal(cont["Iris-setosa"], correct) + self.assertEqual(cont.unknowns, 0) + + correct = [[2.2, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.6, 3.8], + [1, 4, 2, 4, 8, 2, 12, 4, 5, 3, 2, 1, 2]] + np.testing.assert_almost_equal( + cont[d.domain.class_var.values.index("Iris-virginica")], correct) + np.testing.assert_almost_equal(cont.col_unknowns, [0, 0, 0]) + np.testing.assert_almost_equal(cont.row_unknowns, np.zeros(23)) + self.assertEqual(cont.unknowns, 0) + + def test_continuous_missing(self): + d = data.Table("iris") + d[1][1] = float("nan") + cont = contingency.Continuous(d, "sepal width") + correct = [[2.3, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, + 3.8, 3.9, 4.0, 4.1, 4.2, 4.4], + [1, 1, 5, 5, 5, 2, 9, 6, 2, 3, 4, 2, 1, 1, 1, 1]] + np.testing.assert_almost_equal(cont.col_unknowns, [1, 0, 0]) + np.testing.assert_almost_equal(cont.row_unknowns, np.zeros(23)) + np.testing.assert_almost_equal(cont["Iris-setosa"], correct) + self.assertEqual(cont.unknowns, 0) + + d.Y[0] = float("nan") + cont = contingency.Continuous(d, "sepal width") + correct = [[2.2, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.6, 3.8], + [1, 4, 2, 4, 8, 2, 12, 4, 5, 3, 2, 1, 2]] + np.testing.assert_almost_equal( + cont[d.domain.class_var.values.index("Iris-virginica")], correct) + np.testing.assert_almost_equal(cont.col_unknowns, [1, 0, 0]) + np.testing.assert_almost_equal( + cont.row_unknowns, + [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., + 0., 0., 0., 0., 0., 0., 0.]) + self.assertEqual(cont.unknowns, 0) + + d.Y[1] = float("nan") + cont = contingency.Continuous(d, "sepal width") + np.testing.assert_almost_equal(cont.col_unknowns, [0, 0, 0]) + np.testing.assert_almost_equal( + cont.row_unknowns, + [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., + 0., 0., 0., 0., 0., 0., 0.]) + self.assertEqual(cont.unknowns, 1) + + # this one was failing before since the issue in _contingecy.pyx + d.Y[:50] = np.zeros(50) * float("nan") + cont = contingency.Continuous(d, "sepal width") + np.testing.assert_almost_equal(cont.col_unknowns, [0, 0, 0]) + np.testing.assert_almost_equal( + cont.row_unknowns, + [0., 0., 1., 0., 0., 0., 0., 0., 1., 5., 5., 5., 2., 9., 6., 2., + 3., 4., 2., 1., 1., 1., 1.]) + self.assertEqual(cont.unknowns, 1) + + @staticmethod + def test_continuous_array_with_unknowns(): + """ + Test array_with_unknowns function + """ + d = data.Table("iris") + d.Y[:50] = np.zeros(50) * float("nan") + cont = contingency.Continuous(d, "sepal width") + correct_row_unknowns = [0., 0., 1., 0., 0., 0., 0., 0., 1., 6., 5., 5., + 2., 9., 6., 2., 3., 4., 2., 1., 1., 1., 1.] + correct_row_unknowns_no_zero = [ + c for c in correct_row_unknowns if c > 0] + correct_values_no_zero = [ + v for v, c in zip(cont.values, correct_row_unknowns) if c > 0] + + np.testing.assert_almost_equal(cont.row_unknowns, correct_row_unknowns) + arr_unknowns = cont.array_with_unknowns + np.testing.assert_almost_equal( + arr_unknowns[-1][1], correct_row_unknowns_no_zero) + np.testing.assert_almost_equal( + arr_unknowns[-1][0], correct_values_no_zero) + + # check if other match to what we get with __getitem__ + for v1, v2 in zip(arr_unknowns[:-1], cont): + np.testing.assert_almost_equal(v1, v2) + + def test_mixedtype_metas(self): + import Orange + zoo = Orange.data.Table("zoo") + dom = Orange.data.Domain(zoo.domain.attributes, zoo.domain.class_var, + zoo.domain.metas + zoo.domain.attributes[:2]) + t = zoo.transform(dom) + cont = contingency.get_contingency(zoo, 2, t.domain.metas[1]) + assert_dist_equal(cont["1"], [38, 5]) + assert_dist_equal(cont, [[4, 54], [38, 5]]) + zoo[25][t.domain.metas[1]] = float("nan") + zoo[0][2] = float("nan") + cont = contingency.get_contingency(zoo, 2, t.domain.metas[1]) + assert_dist_equal(cont["1"], [37, 5]) + assert_dist_equal(cont, [[4, 53], [37, 5]]) + np.testing.assert_almost_equal(cont.col_unknowns, [0, 1]) + np.testing.assert_almost_equal(cont.row_unknowns, [0, 1]) + self.assertEqual(0, cont.unknowns) + + @staticmethod + def _construct_sparse(): + domain = data.Domain( + [data.DiscreteVariable("d%i" % i, values=list("abc")) + for i in range(10)] + + [data.ContinuousVariable("c%i" % i) for i in range(10)], + data.DiscreteVariable("y", values=list("abc"))) + + # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + #------------------------------------------------------------ + # 2 2 1 1 2 1 1 1 2 0 2 + # 1 1 0 0 1 2 2 1 0 + # 1 2 0 + # + # 2 0 1 1.1 + # + sdata = np.array([2, 2, 1, 1, 2, 1, 1, 1, 2, 0, 2, + 1, 1, 0, 0, 1, 2, 2, 1, 0, + 1, 2, 0, + 2, 0, 1, 1.1]) + indices = [1, 3, 4, 5, 6, 9, 13, 14, 16, 17, 18, + 2, 3, 4, 5, 6, 8, 14, 16, 17, + 3, 5, 6, + 2, 5, 6, 13] + indptr = [0, 11, 20, 23, 23, 27] + X = sp.csr_matrix((sdata, indices, indptr), shape=(5, 20)) + Y = np.array([[1, 2, 1, 0, 0]]).T + return data.Table.from_numpy(domain, X, Y) + + def test_sparse(self): + d = self._construct_sparse() + cont = contingency.Discrete(d, 5) + assert_dist_equal(cont[0], [2, 0, 0]) + assert_dist_equal(cont["b"], [0, 1, 1]) + assert_dist_equal(cont[2], [1, 0, 0]) + + cont = contingency.Continuous(d, 14) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[2], [1]]) + + cont = contingency.Continuous(d, "c3") + assert_dist_equal(cont[0], [[1.1], [1]]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[], []]) + + d[4].set_class(1) + cont = contingency.Continuous(d, 13) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[1, 1.1], [1, 1]]) + assert_dist_equal(cont[2], [[], []]) + + cont = contingency.Continuous(d, 12) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[], []]) + assert_dist_equal(cont[2], [[], []]) + + + def test_get_contingency(self): + d = self._construct_sparse() + cont = contingency.get_contingency(d, 5) + self.assertIsInstance(cont, contingency.Discrete) + assert_dist_equal(cont[0], [2, 0, 0]) + assert_dist_equal(cont["b"], [0, 1, 1]) + assert_dist_equal(cont[2], [1, 0, 0]) + + cont = contingency.get_contingency(d, "c4") + self.assertIsInstance(cont, contingency.Continuous) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[2], [1]]) + + cont = contingency.get_contingency(d, d.domain[13]) + self.assertIsInstance(cont, contingency.Continuous) + assert_dist_equal(cont[0], [[1.1], [1]]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[], []]) + assert_dist_equal(cont[2], [[], []]) + + def test_get_contingencies(self): + d = self._construct_sparse() + conts = contingency.get_contingencies(d) + + self.assertEqual(len(conts), 20) + + cont = conts[5] + self.assertIsInstance(cont, contingency.Discrete) + assert_dist_equal(cont[0], [2, 0, 0]) + assert_dist_equal(cont["b"], [0, 1, 1]) + assert_dist_equal(cont[2], [1, 0, 0]) + + cont = conts[14] + self.assertIsInstance(cont, contingency.Continuous) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[2], [1]]) + + conts = contingency.get_contingencies(d, skip_discrete=True) + self.assertEqual(len(conts), 10) + cont = conts[4] + self.assertIsInstance(cont, contingency.Continuous) + assert_dist_equal(cont[0], [[], []]) + assert_dist_equal(cont["b"], [[1], [1]]) + assert_dist_equal(cont[2], [[2], [1]]) + + conts = contingency.get_contingencies(d, skip_continuous=True) + self.assertEqual(len(conts), 10) + cont = conts[5] + self.assertIsInstance(cont, contingency.Discrete) + assert_dist_equal(cont[0], [2, 0, 0]) + assert_dist_equal(cont["b"], [0, 1, 1]) + assert_dist_equal(cont[2], [1, 0, 0]) + + def test_compute_contingency_metas(self): + var1, var2 = self.test9.domain[-2], self.test9.domain[-4] + cont = contingency.Discrete(self.test9, var1, var2) + assert_dist_equal(cont, [[3, 0, 0], [0, 2, 0], + [0, 0, 2], [0, 1, 0]]) + + def test_compute_contingency_row_attribute_sparse(self): + """ + Testing with sparse row variable since currently we do not test the + situation when a row variable is sparse. + """ + d = self.test9 + # make X sparse + d.X = csr_matrix(d.X) + var1, var2 = d.domain[0], d.domain[1] + cont = contingency.Discrete(d, var1, var2) + assert_dist_equal(cont, [[1, 0], [1, 0], [1, 0], [1, 0], + [0, 1], [0, 1], [0, 1], [0, 1]]) + cont = contingency.Discrete(d, var2, var1) + assert_dist_equal(cont, [[1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1]]) + + d.X = csc_matrix(d.X) + cont = contingency.Discrete(d, var1, var2) + assert_dist_equal(cont, [[1, 0], [1, 0], [1, 0], [1, 0], + [0, 1], [0, 1], [0, 1], [0, 1]]) + cont = contingency.Discrete(d, var2, var1) + assert_dist_equal(cont, [[1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1]]) + + def test_compute_contingency_invalid(self): + rstate = np.random.RandomState(0xFFFF) + X = data.ContinuousVariable("X") + C = data.DiscreteVariable("C", values=["C{}".format(i + 1) for i in range(1024)]) + domain = data.Domain([X], [C]) + d = data.Table.from_numpy( + domain, + rstate.uniform(size=(20, 1)).round(1), + rstate.randint(0, 1024, size=(20, 1)), + ) + c = contingency.get_contingency(d, X, C) + self.assertEqual(c.counts.shape[0], 1024) + + d.Y[5] = 1024 + with self.assertRaises(IndexError): + contingency.get_contingency(d, X, C) + + def test_incompatible_arguments(self): + """ + When providing data table unknowns should not be provided + """ + self.assertRaises( + TypeError, contingency.Discrete, self.zoo, 0, unknowns=0) + self.assertRaises( + TypeError, contingency.Discrete, self.zoo, 0, row_unknowns=0) + self.assertRaises( + TypeError, contingency.Discrete, self.zoo, 0, col_unknowns=0) + + self.assertRaises( + TypeError, contingency.Continuous, self.zoo, 0, unknowns=0) + self.assertRaises( + TypeError, contingency.Continuous, self.zoo, 0, row_unknowns=0) + self.assertRaises( + TypeError, contingency.Continuous, self.zoo, 0, col_unknowns=0) + + # data with no class + zoo_ = Table.from_table(Domain(self.zoo.domain.attributes), self.zoo) + self.assertRaises(ValueError, contingency.Discrete, zoo_, 0) + self.assertRaises(ValueError, contingency.Continuous, zoo_, 0) diff --git a/pyminer2/tests/test_continuize.py b/pyminer2/tests/test_continuize.py new file mode 100644 index 0000000000000000000000000000000000000000..1cb1d5c5cfaa1599323ae2be7b670e63734e87b1 --- /dev/null +++ b/pyminer2/tests/test_continuize.py @@ -0,0 +1,195 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table, Variable +from Orange.preprocess.continuize import DomainContinuizer +from Orange.preprocess import Continuize +from Orange.preprocess import transformation +from Orange.tests import test_filename + + +class TestDomainContinuizer(unittest.TestCase): + def setUp(self): + self.data = Table(test_filename("datasets/test4")) + + def test_default(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer() + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertIs(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2", "d2=a", "d2=b", "d3=a", "d3=b", "d3=c"]) + self.assertIsInstance(dom[2].compute_value, transformation.Indicator) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 1, 0, 1, 0, 0, "a"]) + self.assertEqual(dat2[1], [0, 0, 0, 1, 0, 1, 0, "b"]) + self.assertEqual(dat2[2], [2, 2, 0, 1, 0, 0, 1, "c"]) + + def test_continuous_transform_class(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(transform_class=True) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.variables)) + self.assertIsNot(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2", "d2=a", "d2=b", "d3=a", "d3=b", "d3=c"]) + self.assertIsInstance(dom[2].compute_value, transformation.Indicator) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 1, 0, 1, 0, 0, 1, 0, 0]) + self.assertEqual(dat2[1], [0, 0, 0, 1, 0, 1, 0, 0, 1, 0]) + self.assertEqual(dat2[2], [2, 2, 0, 1, 0, 0, 1, 0, 0, 1]) + + def test_multi_indicators(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(multinomial_treatment=Continuize.Indicators) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertIs(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2", "d2=a", "d2=b", "d3=a", "d3=b", + "d3=c"]) + self.assertIsInstance(dom[2].compute_value, + transformation.Indicator) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 1, 0, 1, 0, 0, "a"]) + self.assertEqual(dat2[1], [0, 0, 0, 1, 0, 1, 0, "b"]) + self.assertEqual(dat2[2], [2, 2, 0, 1, 0, 0, 1, "c"]) + + def test_multi_lowest_base(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(multinomial_treatment=Continuize.FirstAsBase) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertIs(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2", "d2=b", "d3=b", "d3=c"]) + self.assertIsInstance(dom[2].compute_value, + transformation.Indicator) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 0, 0, 0, "a"]) + self.assertEqual(dat2[1], [0, 0, 1, 1, 0, "b"]) + self.assertEqual(dat2[2], [2, 2, 1, 0, 1, "c"]) + + def test_multi_ignore(self): + dom = DomainContinuizer(multinomial_treatment=Continuize.Remove) + dom = dom(self.data.domain) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2"]) + + def test_multi_ignore_class(self): + dom = DomainContinuizer(multinomial_treatment=Continuize.Remove, + transform_class=True) + dom = dom(self.data.domain) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2"]) + self.assertEqual(len(dom.class_vars), 0) + self.assertIsNone(dom.class_var) + + def test_multi_ignore_multi(self): + dom = DomainContinuizer( + multinomial_treatment=Continuize.RemoveMultinomial) + dom = dom(self.data.domain) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertEqual([attr.name for attr in dom.variables], + ["c1", "c2", "d2=b", "cl1"]) + + def test_multi_ignore_class(self): + dom = DomainContinuizer( + multinomial_treatment=Continuize.RemoveMultinomial, + transform_class=True) + dom = dom(self.data.domain) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertEqual([attr.name for attr in dom.attributes], + ["c1", "c2", "d2=b"]) + self.assertEqual(len(dom.class_vars), 0) + self.assertIsNone(dom.class_var) + + def test_multi_error(self): + self.assertRaises(ValueError, + DomainContinuizer( + multinomial_treatment=Continuize.ReportError), + self.data.domain) + + def test_as_ordinal(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(multinomial_treatment=Continuize.AsOrdinal) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertIs(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.variables], + ["c1", "c2", "d2", "d3", "cl1"]) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 0, 0, "a"]) + self.assertEqual(dat2[1], [0, 0, 1, 1, "b"]) + self.assertEqual(dat2[2], [2, 2, 1, 2, "c"]) + + def test_as_ordinal_class(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(multinomial_treatment=Continuize.AsOrdinal, + transform_class=True) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertTrue(dom.has_continuous_class) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.variables], + ["c1", "c2", "d2", "d3", "cl1"]) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 0, 0, 0]) + self.assertEqual(dat2[1], [0, 0, 1, 1, 1]) + self.assertEqual(dat2[2], [2, 2, 1, 2, 2]) + + def test_as_normalized_ordinal(self): + for inp in (self.data, self.data.domain): + dom = DomainContinuizer(multinomial_treatment=Continuize.AsNormalizedOrdinal) + dom = dom(inp) + self.assertTrue(all(attr.is_continuous + for attr in dom.attributes)) + self.assertIs(dom.class_var, self.data.domain.class_var) + self.assertIs(dom[0], self.data.domain[0]) + self.assertIs(dom[1], self.data.domain[1]) + self.assertEqual([attr.name for attr in dom.variables], + ["c1", "c2", "d2", "d3", "cl1"]) + + dat2 = self.data.transform(dom) + # c1 c2 d2 d3 cl1 + self.assertEqual(dat2[0], [1, -2, 0, 0, "a"]) + self.assertEqual(dat2[1], [0, 0, 1, 0.5, "b"]) + self.assertEqual(dat2[2], [2, 2, 1, 1, "c"]) diff --git a/pyminer2/tests/test_cur.py b/pyminer2/tests/test_cur.py new file mode 100644 index 0000000000000000000000000000000000000000..ab2c234da8d9311839bed306b927d3a3e09157bb --- /dev/null +++ b/pyminer2/tests/test_cur.py @@ -0,0 +1,59 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np +import scipy.sparse.linalg as sla + +import Orange +from Orange.projection import CUR +from Orange.tests import test_filename + + +class TestCUR(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.ionosphere = Orange.data.Table(test_filename('datasets/ionosphere.tab')) + + def test_cur_projection(self): + self.__projection_test_helper(self.ionosphere, rank=10, max_error=10) + self.__projection_test_helper(self.ionosphere, rank=20, max_error=10) + self.__projection_test_helper(self.ionosphere, rank=5, max_error=1) + + def __projection_test_helper(self, data, rank, max_error): + cur = CUR(rank=rank, max_error=max_error) + cur_model = cur(data) + self.assertEqual(data.X.shape[0], cur_model.C_.shape[0]) + self.assertEqual(data.X.shape[1], cur_model.R_.shape[1]) + np.testing.assert_array_equal(cur_model(data).X, cur_model.C_) + + def test_cur_reconstruction(self): + self.__reconstruction_test_helper(self.ionosphere, rank=20, max_error=5) + self.__reconstruction_test_helper(self.ionosphere, rank=25, max_error=1) + self.__reconstruction_test_helper(self.ionosphere, rank=30, max_error=0.1) + + def __reconstruction_test_helper(self, data, rank, max_error): + U, s, V = sla.svds(data.X, rank) + S = np.diag(s) + X_k = np.dot(U, np.dot(S, V)) + err_svd = np.linalg.norm(data.X - X_k, 'fro') + cur = CUR(rank=rank, max_error=max_error, compute_U=True, random_state=0) + cur_model = cur(data) + X_hat = np.dot(cur_model.C_, np.dot(cur_model.U_, cur_model.R_)) + err_cur = np.linalg.norm(data.X - X_hat, 'fro') + self.assertLess(err_cur, (3 + cur_model.max_error) * err_svd) + + def test_cur_axis(self): + data1 = self.ionosphere[:100] + data2 = self.ionosphere[100:] + cur = CUR(rank=5, max_error=1) + cur_model = cur(data1) + + data2_trans1 = cur_model(data2) + data2_trans2 = data2.X[:, cur_model.features_] + np.testing.assert_array_equal(data2_trans1.X, data2_trans2) + + data1_trans1 = cur_model(data1, axis=1) + data1_trans2 = data1.X[cur_model.samples_, :] + np.testing.assert_array_equal(data1_trans1.X, data1_trans2) diff --git a/pyminer2/tests/test_data_util.py b/pyminer2/tests/test_data_util.py new file mode 100644 index 0000000000000000000000000000000000000000..efe28f3c40f1462856575cd99e8787d81738d60e --- /dev/null +++ b/pyminer2/tests/test_data_util.py @@ -0,0 +1,74 @@ +import unittest +from unittest.mock import Mock + +import numpy as np + +from Orange.data.util import scale, one_hot, SharedComputeValue +import Orange + +class TestDataUtil(unittest.TestCase): + def test_scale(self): + np.testing.assert_equal(scale([0, 1, 2], -1, 1), [-1, 0, 1]) + np.testing.assert_equal(scale([3, 3, 3]), [1, 1, 1]) + np.testing.assert_equal(scale([.1, .5, np.nan]), [0, 1, np.nan]) + np.testing.assert_equal(scale(np.array([])), np.array([])) + + def test_one_hot(self): + np.testing.assert_equal( + one_hot([0, 1, 2, 1], int), [[1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [0, 1, 0]]) + np.testing.assert_equal(one_hot([], int), np.zeros((0, 0), dtype=int)) + + +class DummyPlus(SharedComputeValue): + + def compute(self, data, shared_data): + return data.X[:, 0] + shared_data + + +class DummyTable(Orange.data.Table): + pass + + +class TestSharedComputeValue(unittest.TestCase): + + def test_compat_compute_value(self): + data = Orange.data.Table("iris") + obj = DummyPlus(lambda data: 1.) + res = obj(data) + obj = lambda data: data.X[:, 0] + 1. + res2 = obj(data) + np.testing.assert_equal(res, res2) + + def test_with_row_indices(self): + obj = DummyPlus(lambda data: 1.) + data = Orange.data.Table("iris") + domain = Orange.data.Domain([Orange.data.ContinuousVariable("cv", compute_value=obj)]) + data1 = Orange.data.Table.from_table(domain, data)[:10] + data2 = Orange.data.Table.from_table(domain, data, range(10)) + np.testing.assert_equal(data1.X, data2.X) + + def test_single_call(self): + obj = DummyPlus(Mock(return_value=1)) + self.assertEqual(obj.compute_shared.call_count, 0) + data = Orange.data.Table("iris") + domain = Orange.data.Domain([at.copy(compute_value=obj) + for at in data.domain.attributes], + data.domain.class_vars) + + Orange.data.Table.from_table(domain, data) + self.assertEqual(obj.compute_shared.call_count, 1) + ndata = Orange.data.Table.from_table(domain, data) + self.assertEqual(obj.compute_shared.call_count, 2) + + #the learner performs imputation + c = Orange.classification.LogisticRegressionLearner()(ndata) + self.assertEqual(obj.compute_shared.call_count, 2) + c(data) #the new data should be converted with one call + self.assertEqual(obj.compute_shared.call_count, 3) + + #test with descendants of table + DummyTable.from_table(c.domain, data) + self.assertEqual(obj.compute_shared.call_count, 4) diff --git a/pyminer2/tests/test_datasets.py b/pyminer2/tests/test_datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..3d309c04b5c2463067f193280043e5cb50b9843f --- /dev/null +++ b/pyminer2/tests/test_datasets.py @@ -0,0 +1,70 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import os + +from Orange.data import Table, Variable +from Orange import datasets + + +class TestDatasets(unittest.TestCase): + def test_access(self): + d1 = datasets.iris + fname = datasets.iris['location'] + d2 = datasets['iris'] + self.assertNotEqual(len(d1), 0) + self.assertEqual(len(d1), len(d2)) + + def test_filter(self): + for info in datasets.values(): + if info['features']['continuous'] == 0: + data = Table(info['location']) + self.assertFalse(data.domain.has_continuous_attributes()) + + def test_have_all(self): + datasets_folder = os.path.join(os.path.dirname(__file__), + '../datasets') + for fname in os.listdir(datasets_folder): + if not os.path.isfile(os.path.join(datasets_folder, fname)): + continue + name, ext = os.path.splitext(fname) + if ext != '.tab': + continue + self.assertIn(name, datasets) + + def test_datasets_info_features(self): + for dataset, info in datasets.items(): + + if info['location'].startswith('http'): continue # Tested elsewhere + + table = Table(dataset) + domain = table.domain + + # Test features + self.assertEqual(table.X.shape[0], info['rows'], dataset) + self.assertEqual(table.has_missing(), info['missing'], dataset) + self.assertEqual(len(domain.metas), info['features']['meta'], dataset) + self.assertEqual(sum(i.is_discrete for i in domain.attributes), + info['features']['discrete'], + dataset) + self.assertEqual(sum(i.is_continuous for i in domain.attributes), + info['features']['continuous'], + dataset) + + # Test class vars + if len(domain.class_vars) > 1: + self.assertEqual(['discrete' if i.is_discrete else 'continuous' + for i in domain.class_vars], + info['target']['type'], + dataset) + elif len(domain.class_vars) == 1: + cls = domain.class_var + self.assertEqual('discrete' if cls.is_discrete else 'continuous', + info['target']['type'], + dataset) + if cls.is_discrete: + self.assertEqual(len(cls.values), info['target']['values'], dataset) + else: + self.assertEqual(False, info['target']['type'], dataset) diff --git a/pyminer2/tests/test_discretize.py b/pyminer2/tests/test_discretize.py new file mode 100644 index 0000000000000000000000000000000000000000..f93bfff9a1941c691e8e532394423372fabbfa0c --- /dev/null +++ b/pyminer2/tests/test_discretize.py @@ -0,0 +1,322 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import random +from unittest import TestCase + +import numpy as np +import scipy.sparse as sp + +from Orange.preprocess import discretize, Discretize +from Orange import data +from Orange.data import Table, Instance, Domain, ContinuousVariable, DiscreteVariable + + +# noinspection PyPep8Naming +from Orange.widgets.tests.utils import table_dense_sparse + + +class TestEqualFreq(TestCase): + def test_equifreq_with_too_few_values(self): + s = [0] * 50 + [1] * 50 + random.shuffle(s) + X = np.array(s).reshape((100, 1)) + table = data.Table.from_numpy(None, X) + disc = discretize.EqualFreq(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 2) + self.assertEqual(dvar.compute_value.points, [0.5]) + + def test_equifreq_100_to_4(self): + X = np.arange(100).reshape((100, 1)) + table = data.Table.from_numpy(None, X) + disc = discretize.EqualFreq(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 4) + self.assertEqual(dvar.compute_value.points, [24.5, 49.5, 74.5]) + + def test_equifreq_with_k_instances(self): + X = np.array([[1], [2], [3], [4]]) + table = data.Table.from_numpy(None, X) + disc = discretize.EqualFreq(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 4) + self.assertEqual(dvar.compute_value.points, [1.5, 2.5, 3.5]) + + +# noinspection PyPep8Naming +class TestEqualWidth(TestCase): + def test_equalwidth_on_two_values(self): + s = [0] * 50 + [1] * 50 + random.shuffle(s) + X = np.array(s).reshape((100, 1)) + table = data.Table.from_numpy(None, X) + disc = discretize.EqualWidth(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 4) + self.assertEqual(dvar.compute_value.points, [0.25, 0.5, 0.75]) + + @table_dense_sparse + def test_equalwidth_100_to_4(self, prepare_table): + X = np.arange(101).reshape((101, 1)) + table = prepare_table(data.Table.from_numpy(None, X)) + disc = discretize.EqualWidth(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 4) + self.assertEqual(dvar.compute_value.points, [25, 50, 75]) + + def test_equalwidth_const_value(self): + X = np.ones((100, 1)) + table = data.Table.from_numpy(None, X) + disc = discretize.EqualFreq(n=4) + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 1) + self.assertEqual(dvar.compute_value.points, []) + + +# noinspection PyPep8Naming +class TestEntropyMDL(TestCase): + def test_entropy_with_two_values(self): + s = [0] * 50 + [1] * 50 + random.shuffle(s) + X = np.array(s).reshape((100, 1)) + table = data.Table.from_numpy(None, X, X) + disc = discretize.EntropyMDL() + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 2) + self.assertEqual(dvar.compute_value.points, [0.5]) + + def test_entropy_with_two_values_useless(self): + X = np.array([0] * 50 + [1] * 50).reshape((100, 1)) + Y = np.array([0] * 25 + [1] * 50 + [0] * 25) + table = data.Table.from_numpy(None, X, Y) + disc = discretize.EntropyMDL() + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 1) + self.assertEqual(dvar.compute_value.points, []) + + def test_entropy_constant(self): + X = np.zeros((100, 1)) + domain = Domain([ContinuousVariable('v1')], + [DiscreteVariable('c1', values=["1"])]) + table = data.Table(domain, X, X) + disc = discretize.EntropyMDL() + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 1) + self.assertEqual(dvar.compute_value.points, []) + + def test_entropy(self): + X = np.array([0] * 25 + [1] * 25 + [2] * 25 + [3] * 25 + ).reshape((100, 1)) + Y = np.array([0] * 25 + [1] * 75) + table = data.Table.from_numpy(None, X, Y) + disc = discretize.EntropyMDL() + dvar = disc(table, table.domain[0]) + self.assertEqual(len(dvar.values), 2) + self.assertEqual(dvar.compute_value.points, [0.5]) + + +# noinspection PyPep8Naming +class TestDiscretizer(TestCase): + def setUp(self): + self.var = data.ContinuousVariable("x", number_of_decimals=1) + + def test_create_discretized_var(self): + dvar = discretize.Discretizer.create_discretized_var( + self.var, [1, 2, 3]) + self.assertIsInstance(dvar.compute_value, + discretize.Discretizer) + self.assertEqual(dvar.compute_value.points, [1, 2, 3]) + + + def test_create_discretized_var_formatting(self): + dvar = discretize.Discretizer.create_discretized_var( + self.var, [1, 2, 3]) + self.assertEqual(dvar.values, ["< 1", "1 - 2", "2 - 3", "≥ 3"]) + + dvar = discretize.Discretizer.create_discretized_var( + self.var, [10]) + self.assertEqual(dvar.values, ["< 10", "≥ 10"]) + + dvar = discretize.Discretizer.create_discretized_var( + self.var, [10.1234]) + self.assertEqual(dvar.values, ["< 10.1", "≥ 10.1"]) + + self.var.number_of_decimals = 3 + + dvar = discretize.Discretizer.create_discretized_var( + self.var, [5, 10.1234]) + self.assertEqual(dvar.values, ["< 5", "5 - 10.123", "≥ 10.123"]) + + def test_discretizer_computation(self): + dvar = discretize.Discretizer.create_discretized_var( + self.var, [1, 2, 3]) + X = np.array([0, 0.9, 1, 1.1, 1.9, 2, 2.5, 3, 3.5]) + np.testing.assert_equal(dvar.compute_value.transform(X), np.floor(X)) + + def test_discretizer_computation_sparse(self): + dvar = discretize.Discretizer.create_discretized_var( + self.var, [1, 2, 3]) + X = sp.csr_matrix(np.array([0, 0.9, 1, 1.1, 1.9, 2, 2.5, 3, 3.5])) + self.assertEqual((dvar.compute_value.transform(X) != X.floor()).nnz, 0) + + def test_discretizer_computation_sparse_no_points(self): + dvar = discretize.Discretizer.create_discretized_var( + self.var, []) + X = sp.csr_matrix(np.array([0, 0.9, 1, 1.1, 1.9, 2, 2.5, 3, 3.5])) + empty = sp.csr_matrix(X.shape) + self.assertEqual((dvar.compute_value.transform(X) != empty).nnz, 0) + + def test_transform(self): + table = data.Table('iris') + table2 = Discretize()(table) + ins = data.Instance(table2.domain, table[0]) + table3 = table[:10].transform(table2.domain) + self.assertEqual(ins, table3[0]) + + def test_remove_constant(self): + table = data.Table('iris') + table[:, 0] = 1 + discretize = Discretize(remove_const=True) + new_table = discretize(table) + self.assertNotEqual(len(table.domain.attributes), + len(new_table.domain.attributes)) + + def test_keep_constant(self): + table = data.Table('iris') + table[:, 0] = 1 + discretize = Discretize(remove_const=False) + new_table = discretize(table) + self.assertEqual(len(table.domain.attributes), + len(new_table.domain.attributes)) + + def test_discretize_class(self): + table = data.Table('iris') + domain = table.domain + regr_domain = data.Domain(domain.attributes[:3], + [domain.attributes[3], domain.class_var]) + table = data.Table.from_table(regr_domain, table) + + discretize = Discretize(remove_const=False) + new_table = discretize(table) + self.assertIs(new_table.domain.class_vars[0], + new_table.domain.class_vars[0]) + self.assertIs(new_table.domain.class_vars[1], + new_table.domain.class_vars[1]) + + discretize = Discretize(remove_const=False, discretize_classes=True) + new_table = discretize(table) + self.assertIsInstance(new_table.domain.class_vars[0], DiscreteVariable) + self.assertIs(new_table.domain.class_vars[1], + new_table.domain.class_vars[1]) + + def test_discretize_metas(self): + table = data.Table('iris') + domain = table.domain + regr_domain = data.Domain(domain.attributes[:3], + [], + [domain.attributes[3], domain.class_var]) + table = data.Table.from_table(regr_domain, table) + + discretize = Discretize(remove_const=False) + new_table = discretize(table) + self.assertIs(new_table.domain.metas[0], + new_table.domain.metas[0]) + self.assertIs(new_table.domain.metas[1], + new_table.domain.metas[1]) + + discretize = Discretize(remove_const=False, discretize_metas=True) + new_table = discretize(table) + self.assertIsInstance(new_table.domain.metas[0], DiscreteVariable) + self.assertIs(new_table.domain.metas[1], + new_table.domain.metas[1]) + + +# noinspection PyPep8Naming +class TestDiscretizeTable(TestCase): + @classmethod + def setUpClass(cls): + s = [0] * 50 + [1] * 50 + X1 = np.array(s).reshape((100, 1)) + X2 = np.arange(100).reshape((100, 1)) + X3 = np.ones((100, 1)) + X = np.hstack([X1, X2, X3]) + cls.table_no_class = data.Table.from_numpy(None, X) + cls.table_class = data.Table.from_numpy(None, X, X1) + + def test_discretize_exclude_constant(self): + dom = discretize.DomainDiscretizer()(self.table_no_class) + self.assertEqual(len(dom.attributes), 2) + self.assertEqual(dom[0].compute_value.points, [0.5]) + self.assertEqual(dom[1].compute_value.points, [24.5, 49.5, 74.5]) + + dom = discretize.DomainDiscretizer(clean=False)(self.table_no_class) + self.assertEqual(len(dom.attributes), 3) + self.assertEqual(dom[0].compute_value.points, [0.5]) + self.assertEqual(dom[1].compute_value.points, [24.5, 49.5, 74.5]) + self.assertEqual(dom[2].compute_value.points, []) + + dom = discretize.DomainDiscretizer()(self.table_class) + self.assertEqual(len(dom.attributes), 2) + self.assertEqual(dom[0].compute_value.points, [0.5]) + self.assertEqual(dom[1].compute_value.points, [24.5, 49.5, 74.5]) + + def test_discretize_class(self): + dom = discretize.DomainDiscretizer()(self.table_class) + self.assertIs(dom.class_var, self.table_class.domain.class_var) + + dom = discretize.DomainDiscretizer(discretize_class=True) + dom = dom(self.table_class) + self.assertIs(dom.class_var, self.table_class.domain.class_var) + + def test_method(self): + dom = discretize.DomainDiscretizer()(self.table_class) + self.assertEqual(len(dom[1].values), 4) + + dom = discretize.DomainDiscretizer(method=discretize.EqualWidth(n=2)) + dom = dom(self.table_class) + self.assertEqual(len(dom[1].values), 2) + + def test_fixed(self): + dom = discretize.DomainDiscretizer(method=discretize.EqualWidth(n=2), + fixed={"Feature 2": [1, 11]}) + dom = dom(self.table_no_class) + self.assertEqual(len(dom.attributes), 2) + self.assertEqual(dom[0].compute_value.points, [0.5]) + self.assertEqual(dom[1].compute_value.points, [6]) + + def test_leave_discrete(self): + s = [0] * 50 + [1] * 50 + X1 = np.array(s).reshape((100, 1)) + X2 = np.arange(100).reshape((100, 1)) + X3 = np.ones((100, 1)) + X = np.hstack([X1, X2, X3]) + domain = data.Domain([data.DiscreteVariable("a", values="MF"), + data.ContinuousVariable("b"), + data.DiscreteVariable("c", values="AB")], + data.ContinuousVariable("d")) + table = data.Table(domain, X, X1) + dom = discretize.DomainDiscretizer()(table) + self.assertIs(dom[0], table.domain[0]) + self.assertEqual(dom[1].compute_value.points, [24.5, 49.5, 74.5]) + self.assertIs(dom[2], table.domain[2]) + self.assertIs(dom.class_var, table.domain.class_var) + + domain = data.Domain([data.DiscreteVariable("a", values="MF"), + data.ContinuousVariable("b"), + data.DiscreteVariable("c", values="AB")], + data.DiscreteVariable("d")) + table = data.Table(domain, X, X1) + dom = discretize.DomainDiscretizer()(table) + self.assertIs(dom[0], table.domain[0]) + self.assertEqual(dom[1].compute_value.points, [24.5, 49.5, 74.5]) + self.assertIs(dom[2], table.domain[2]) + self.assertIs(dom.class_var, table.domain.class_var) + + +class TestInstanceConversion(TestCase): + def test_single_instance(self): + iris = Table("iris") + inst = Instance(iris.domain, [5.2, 3.8, 1.4, 0.5, "Iris-virginica"]) + d_iris = Discretize()(iris) + Instance(d_iris.domain, inst) diff --git a/pyminer2/tests/test_distances.py b/pyminer2/tests/test_distances.py new file mode 100644 index 0000000000000000000000000000000000000000..f1f2b985f8d8a917f985203ed9c8c6ebf02d4c67 --- /dev/null +++ b/pyminer2/tests/test_distances.py @@ -0,0 +1,1027 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +from unittest import TestCase +import unittest +import pickle + +import numpy as np +import scipy +import scipy.spatial +import scipy.stats +from scipy.sparse import csr_matrix + +from Orange.data import (Table, Domain, ContinuousVariable, + DiscreteVariable, StringVariable, Instance) +from Orange.distance import (Euclidean, SpearmanR, SpearmanRAbsolute, + PearsonR, PearsonRAbsolute, Manhattan, Cosine, + Jaccard, _preprocess, MahalanobisDistance, + Bhattacharyya) +from Orange.distance.distance import _spearmanr2, _corrcoef2 +from Orange.misc import DistMatrix +from Orange.tests import named_file, test_filename +from Orange.util import OrangeDeprecationWarning + + +def tables_equal(tab1, tab2): + # TODO: introduce Table.__eq__() ??? + return (tab1 == tab2 or # catches None + np.all([i == j for i, j in zip(tab1, tab2)])) + + +class TestDistMatrix(TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.dist = Euclidean(cls.iris) + + # pylint: disable=unsubscriptable-object + def test_submatrix(self): + sub = self.dist.submatrix([2, 3, 4]) + np.testing.assert_equal(sub, self.dist[2:5, 2:5]) + self.assertTrue(tables_equal(sub.row_items, self.dist.row_items[2:5])) + + def test_pickling(self): + unpickled_dist = pickle.loads(pickle.dumps(self.dist)) + np.testing.assert_equal(unpickled_dist, self.dist) + self.assertTrue(tables_equal(unpickled_dist.row_items, + self.dist.row_items)) + self.assertTrue(tables_equal(unpickled_dist.col_items, + self.dist.col_items)) + self.assertEqual(unpickled_dist.axis, self.dist.axis) + + def test_deprecated(self): + a9 = np.arange(9).reshape(3, 3) + m = DistMatrix(a9) + with self.assertWarns(OrangeDeprecationWarning): + self.assertEqual(m.dim, 3) + with self.assertWarns(OrangeDeprecationWarning): + np.testing.assert_almost_equal(m.X, a9) + + def test_from_file(self): + with named_file( + """3 axis=0 asymmetric col_labels row_labels + ann bert chad + danny 0.12 3.45 6.78 + eve 9.01 2.34 5.67 + frank 8.90 1.23 4.56""") as name: + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 3.45, 6.78], + [9.01, 2.34, 5.67], + [8.90, 1.23, 4.56]])) + self.assertIsInstance(m.row_items, Table) + self.assertIsInstance(m.col_items, Table) + self.assertEqual([e.metas[0] for e in m.col_items], + ["ann", "bert", "chad"]) + self.assertEqual([e.metas[0] for e in m.row_items], + ["danny", "eve", "frank"]) + self.assertEqual(m.axis, 0) + + with named_file( + """3 axis=1 row_labels + danny 0.12 3.45 6.78 + eve 9.01 2.34 5.67 + frank 8.90""") as name: + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 9.01, 8.90], + [9.01, 2.34, 0], + [8.90, 0, 0]])) + self.assertIsInstance(m.row_items, Table) + self.assertIsNone(m.col_items) + self.assertEqual([e.metas[0] for e in m.row_items], + ["danny", "eve", "frank"]) + self.assertEqual(m.axis, 1) + + with named_file( + """3 axis=1 symmetric + 0.12 3.45 6.78 + 9.01 2.34 5.67 + 8.90""") as name: + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 9.01, 8.90], + [9.01, 2.34, 0], + [8.90, 0, 0]])) + + with named_file( + """3 row_labels + starič 0.12 3.45 6.78 + aleš 9.01 2.34 5.67 + anže 8.90""", encoding="utf-8""") as name: + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 9.01, 8.90], + [9.01, 2.34, 0], + [8.90, 0, 0]])) + self.assertIsInstance(m.row_items, Table) + self.assertIsNone(m.col_items) + self.assertEqual([e.metas[0] for e in m.row_items], + ["starič", "aleš", "anže"]) + self.assertEqual(m.axis, 1) + + def assertErrorMsg(content, msg): + with named_file(content) as name: + with self.assertRaises(ValueError) as cm: + DistMatrix.from_file(name) + self.assertEqual(str(cm.exception), msg) + + assertErrorMsg("", + "empty file") + assertErrorMsg("axis=1\n1\t3\n4", + "distance file must begin with dimension") + assertErrorMsg("3 col_labels\na\tb\n1\n\2\n3", + "mismatching number of column labels") + assertErrorMsg("3 col_labels\na\tb\tc\td\n1\n\2\n3", + "mismatching number of column labels") + assertErrorMsg("2\n 1\t2\t3\n 5", + "too many columns in matrix row 1") + assertErrorMsg("2 row_labels\na\t1\t2\t3\nb\t5", + "too many columns in matrix row 'a'") + assertErrorMsg("2 noflag\n 1\t2\t3\n 5", + "invalid flag 'noflag'") + assertErrorMsg("2 noflag=5\n 1\t2\t3\n 5", + "invalid flag 'noflag=5'") + assertErrorMsg("2\n1\n2\n3", + "too many rows") + assertErrorMsg("2\n1\nasd", + "invalid element at row 2, column 1") + assertErrorMsg("2 row_labels\na\t1\nb\tasd", + "invalid element at row 'b', column 1") + assertErrorMsg("2 col_labels row_labels\nd\te\na\t1\nb\tasd", + "invalid element at row 'b', column 'd'") + assertErrorMsg("2 col_labels\nd\te\n1\nasd", + "invalid element at row 2, column 'd'") + + def test_save(self): + with named_file( + """3 axis=1 row_labels + danny 0.12 3.45 6.78 + eve 9.01 2.34 5.67 + frank 8.90""") as name: + m = DistMatrix.from_file(name) + m.save(name) + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 9.01, 8.90], + [9.01, 2.34, 0], + [8.90, 0, 0]])) + self.assertIsInstance(m.row_items, Table) + self.assertIsNone(m.col_items) + self.assertEqual([e.metas[0] for e in m.row_items], + ["danny", "eve", "frank"]) + self.assertEqual(m.axis, 1) + + with named_file( + """3 axis=0 asymmetric col_labels row_labels + ann bert chad + danny 0.12 3.45 6.78 + eve 9.01 2.34 5.67 + frank 8.90 1.23 4.56""") as name: + m = DistMatrix.from_file(name) + m.save(name) + m = DistMatrix.from_file(name) + np.testing.assert_almost_equal(m, np.array([[0.12, 3.45, 6.78], + [9.01, 2.34, 5.67], + [8.90, 1.23, 4.56]])) + self.assertIsInstance(m.row_items, Table) + self.assertIsInstance(m.col_items, Table) + self.assertEqual([e.metas[0] for e in m.col_items], + ["ann", "bert", "chad"]) + self.assertEqual([e.metas[0] for e in m.row_items], + ["danny", "eve", "frank"]) + self.assertEqual(m.axis, 0) + + def test_numpy_type(self): + """GH-3658""" + data1 = np.array([1, 2], dtype=np.int64) + data2 = np.array([2, 3], dtype=np.int64) + dm1, dm2 = DistMatrix(data1), DistMatrix(data2) + + self.assertIsInstance(dm1.max(), np.int64) + self.assertNotIsInstance(dm1.max(), int) + with self.assertRaises(AssertionError): + np.testing.assert_array_equal(dm1, dm2) + + +# noinspection PyTypeChecker +class TestEuclidean(TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.sparse = Table.from_numpy( + None, csr_matrix([[1, 2, 0], [0, 0, 3], [4, 0, 5]])) + cls.dist = Euclidean + + def test_euclidean_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.iris[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1]), + np.array([[0.53851648071346281]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1], axis=1), + np.array([[0.53851648071346281]])) + + def test_euclidean_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.iris[:2]), + np.array([[0., 0.53851648], + [0.53851648, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], axis=0), + np.array([[0., 2.48394847, 5.09313263, 6.78969808], + [2.48394847, 0., 2.64007576, 4.327817], + [5.09313263, 2.64007576, 0., 1.69705627], + [6.78969808, 4.327817, 1.69705627, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2], self.iris[:3]), + np. array([[0.50990195, 0.3, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[3]), + np.array([[0.64807407], + [0.33166248]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[:3]), + np.array([[0., 0.53851648, 0.50990195], + [0.53851648, 0., 0.3]])) + + def test_euclidean_distance_sparse(self): + np.testing.assert_almost_equal( + self.dist(self.sparse), + np.array([[0., 3.74165739, 6.164414], + [3.74165739, 0., 4.47213595], + [6.164414, 4.47213595, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.sparse, axis=0), + np.array([[0., 4.12310563, 3.31662479], + [4.12310563, 0., 6.164414], + [3.31662479, 6.164414, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.sparse[:2]), + np.array([[0., 3.74165739], + [3.74165739, 0.]])) + + def test_euclidean_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X), + np.array([[0., 0.53851648], + [0.53851648, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2].x, self.iris[:3].X), + np. array([[0.50990195, 0.3, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[3].x), + np.array([[0.64807407], + [0.33166248]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[:3].X), + np.array([[0., 0.53851648, 0.50990195], + [0.53851648, 0., 0.3]])) + + +# noinspection PyTypeChecker +class TestManhattan(TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.sparse = Table.from_numpy( + None, csr_matrix([[1, 2, 0], [0, 0, 3], [4, 0, 5]])) + cls.dist = Manhattan + + def test_manhattan_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.iris[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1]), + np.array([[0.7]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1], axis=1), + np.array([[0.7]])) + + def test_manhattan_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.iris[:2]), + np.array([[0., 0.7], + [0.7, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], axis=0), + np.array([[0., 3.5, 7.2, 9.6], + [3.5, 0., 3.7, 6.1], + [7.2, 3.7, 0., 2.4], + [9.6, 6.1, 2.4, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2], self.iris[:3]), + np.array([[0.8, 0.5, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[3]), + np.array([[1.], + [0.5]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[:3]), + np.array([[0., 0.7, 0.8], + [0.7, 0., 0.5]])) + + def test_manhattan_distance_sparse(self): + np.testing.assert_almost_equal( + self.dist(self.sparse), + np.array([[0., 6., 10.], + [6., 0., 6.], + [10., 6., 0.]])) + np.testing.assert_almost_equal( + self.dist(self.sparse, axis=0), + np.array([[0., 5., 5.], + [5., 0., 10.], + [5., 10., 0.]])) + np.testing.assert_almost_equal( + self.dist(self.sparse[:2]), + np.array([[0., 6.], + [6., 0.]])) + + def test_manhattan_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.iris[0].x, self.iris[1].x, axis=1), + np.array([[0.7]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X), + np.array([[0., 0.7], + [0.7, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2].x, self.iris[:3].X), + np.array([[0.8, 0.5, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[3].x), + np.array([[1.], + [0.5]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[:3].X), + np.array([[0., 0.7, 0.8], + [0.7, 0., 0.5]])) + + +# noinspection PyTypeChecker +class TestCosine(TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.sparse = Table.from_numpy( + None, csr_matrix([[1, 2, 0], [0, 0, 3], [4, 0, 5]])) + cls.dist = Cosine + + def test_cosine_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.iris[0]), np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1]), + np.array([[0.00142084]])) + np.testing.assert_almost_equal( + self.dist(self.iris[0], self.iris[1], axis=1), + np.array([[0.00142084]])) + + def test_cosine_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.iris[:2]), + np.array([[0., 1.42083650e-03], + [1.42083650e-03, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], axis=0), + np.array([[0.0, 1.61124231e-03, 1.99940020e-04, 1.99940020e-04], + [1.61124231e-03, 0.0, 2.94551450e-03, 2.94551450e-03], + [1.99940020e-04, 2.94551450e-03, 0.0, 0.0], + [1.99940020e-04, 2.94551450e-03, 0.0, 0.0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2], self.iris[:3]), + np.array([[1.26527175e-05, 1.20854727e-03, 0.0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[3]), + np.array([[0.00089939], + [0.00120607]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2], self.iris[:3]), + np.array([[0.0, 1.42083650e-03, 1.26527175e-05], + [1.42083650e-03, 0.0, 1.20854727e-03]])) + + def test_cosine_distance_sparse(self): + np.testing.assert_almost_equal( + self.dist(self.sparse), + np.array([[0.0, 1.00000000e+00, 7.20627882e-01], + [1.00000000e+00, 0.0, 2.19131191e-01], + [7.20627882e-01, 2.19131191e-01, 0.0]])) + np.testing.assert_almost_equal( + self.dist(self.sparse, axis=0), + np.array([[0.0, 7.57464375e-01, 1.68109669e-01], + [7.57464375e-01, 0.0, 1.00000000e+00], + [1.68109669e-01, 1.00000000e+00, 0.0]])) + np.testing.assert_almost_equal( + self.dist(self.sparse[:2]), + np.array([[0.0, 1.00000000e+00], + [1.00000000e+00, 0.0]])) + + def test_cosine_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.iris[0].x, self.iris[1].x, axis=1), + np.array([[0.00142084]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X), + np.array([[0., 1.42083650e-03], + [1.42083650e-03, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.iris[2].x, self.iris[:3].X), + np.array([[1.26527175e-05, 1.20854727e-03, 0.0]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[3].x), + np.array([[0.00089939], + [0.00120607]])) + np.testing.assert_almost_equal( + self.dist(self.iris[:2].X, self.iris[:3].X), + np.array([[0.0, 1.42083650e-03, 1.26527175e-05], + [1.42083650e-03, 0.0, 1.20854727e-03]])) + + +# noinspection PyTypeChecker +class TestJaccard(TestCase): + @classmethod + def setUpClass(cls): + cls.titanic = Table('titanic')[173:177] + cls.dist = Jaccard + + def test_jaccard_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.titanic[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[0], self.titanic[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[0], self.titanic[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[0], self.titanic[2]), + np.array([[0.5]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[0], self.titanic[2], axis=1), + np.array([[0.5]])) + + def test_jaccard_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.titanic), + np.array([[0., 0., 0.5, 0.5], + [0., 0., 0.5, 0.5], + [0.5, 0.5, 0., 0.], + [0.5, 0.5, 0., 0.]])) + np.testing.assert_almost_equal( + self.dist(self.titanic, axis=0), + np.array([[0., 1., 0.5], + [1., 0., 1.], + [0.5, 1., 0.]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[2], self.titanic[:3]), + np.array([[0.5, 0.5, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[:2], self.titanic[3]), + np.array([[0.5], + [0.5]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[:2], self.titanic[:3]), + np.array([[0., 0., 0.5], + [0., 0., 0.5]])) + + def test_jaccard_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.titanic[0].x, self.titanic[2].x, axis=1), + np.array([[0.5]])) + np.testing.assert_almost_equal( + self.dist(self.titanic.X), + np.array([[0., 0., 0.5, 0.5], + [0., 0., 0.5, 0.5], + [0.5, 0.5, 0., 0.], + [0.5, 0.5, 0., 0.]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[2].x, self.titanic[:3].X), + np.array([[0.5, 0.5, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[:2].X, self.titanic[3].x), + np.array([[0.5], + [0.5]])) + np.testing.assert_almost_equal( + self.dist(self.titanic[:2].X, self.titanic[:3].X), + np.array([[0., 0., 0.5], + [0., 0., 0.5]])) + + +# noinspection PyTypeChecker +class TestSpearmanR(TestCase): + @classmethod + def setUpClass(cls): + cls.breast = Table(test_filename( + "datasets/breast-cancer-wisconsin.tab")) + cls.dist = SpearmanR + + def test_spearmanr_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1]), + np.array([[0.5083333333333333]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1], axis=1), + np.array([[0.5083333333333333]])) + + def test_spearmanr_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.breast[:2]), + np.array([[0., 0.5083333333333333], + [0.5083333333333333, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:4]), + np.array([[0., 0.50833333, 0.075, 0.61666667], + [0.50833333, 0., 0.38333333, 0.53333333], + [0.075, 0.38333333, 0., 0.63333333], + [0.61666667, 0.53333333, 0.63333333, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], axis=0), + np.array([[0., 0.25, 0., 0.25, 0.25, 0.25, 0.75, 0.25, 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.75], + [0., 0.25, 0., 0.25, 0.25, 0.25, 0.75, 0.25, 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.75], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.75], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.75], + [0.75, 0.25, 0.75, 0.25, 0.25, 0.25, 0., 0.25, 1.], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.75], + [0.25, 0.75, 0.25, 0.75, 0.75, 0.75, 1., 0.75, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[:4]), + np.array([[0., 0.50833333, 0.075, 0.61666667], + [0.50833333, 0., 0.38333333, 0.53333333], + [0.075, 0.38333333, 0., 0.63333333]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2], self.breast[:3]), + np.array([[0.075, 0.3833333, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[2]), + np.array([[0.075], + [0.3833333], + [0.]])) + + def test_spearmanr_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0].x, self.breast[1].x, axis=1), + np.array([[0.5083333333333333]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2].X), + np.array([[0., 0.5083333333333333], + [0.5083333333333333, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2].x, self.breast[:3].X), + np.array([[0.075, 0.3833333, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3].X, self.breast[2].x), + np.array([[0.075], + [0.3833333], + [0.]])) + + def test_spearmanr2(self): + # Test that _spearnmanr2 returns the same result that stats.spearmanr + # would + n, m = tuple(np.random.randint(2, 5, size=2)) + mean = np.random.uniform(-1, 1, size=m) + cov = np.random.uniform(0, 1./m, size=(m, m)) + cov = (cov + cov.T) / 2 + cov.flat[::m + 1] = 1.0 + X1 = np.random.multivariate_normal(mean, cov, size=n) + X2 = np.random.multivariate_normal(mean, cov, size=n) + expected = scipy.stats.spearmanr(X1, X2, axis=1)[0][:n, n:] + np.testing.assert_almost_equal( + _spearmanr2(X1, X2, axis=1), + expected, + decimal=9 + ) + + expected = scipy.stats.spearmanr(X1, X2, axis=0)[0][:m, m:] + np.testing.assert_almost_equal( + _spearmanr2(X1, X2, axis=0), + expected, + decimal=9, + ) + + +# noinspection PyTypeChecker +class TestSpearmanRAbsolute(TestCase): + @classmethod + def setUpClass(cls): + cls.breast = Table(test_filename( + "datasets/breast-cancer-wisconsin.tab")) + cls.dist = SpearmanRAbsolute + + def test_spearmanrabsolute_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1]), + np.array([[0.49166666666666664]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1], axis=1), + np.array([[0.49166666666666664]])) + + def test_spearmanrabsolute_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.breast[:2]), + np.array([[0., 0.49166667], + [0.49166667, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], axis=0), + np.array([[0., 0.25, 0., 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.25], + [0., 0.25, 0., 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.25], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.25], + [0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0., 0.25, 0.], + [0.25, 0., 0.25, 0., 0., 0., 0.25, 0., 0.25], + [0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0., 0.25, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[:4]), + np.array([[0., 0.49166667, 0.075, 0.38333333], + [0.49166667, 0., 0.38333333, 0.46666667], + [0.075, 0.38333333, 0., 0.36666667]])) + np.testing.assert_almost_equal( + self.dist(self.breast[3], self.breast[:4]), + np.array([[0.3833333, 0.4666667, 0.3666667, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:4], self.breast[3]), + np.array([[0.3833333], + [0.4666667], + [0.3666667], + [0.]])) + + def test_spearmanrabsolute_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0].x, self.breast[1].x, axis=1), + np.array([[0.49166666666666664]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2].X), + np.array([[0., 0.49166667], + [0.49166667, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[3].x, self.breast[:4].X), + np.array([[0.3833333, 0.4666667, 0.3666667, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:4].X, self.breast[3].x), + np.array([[0.3833333], + [0.4666667], + [0.3666667], + [0.]])) + + +# noinspection PyTypeChecker +class TestPearsonR(TestCase): + @classmethod + def setUpClass(cls): + cls.breast = Table(test_filename( + "datasets/breast-cancer-wisconsin.tab")) + cls.dist = PearsonR + + def test_pearsonr_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1]), + np.array([[0.48462293898088876]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1], axis=1), + np.array([[0.48462293898088876]])) + + def test_pearsonr_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.breast[:2]), + np.array([[0., 0.48462294], + [0.48462294, 0.]])) + # pylint: disable=line-too-long + # Because it looks better + np.testing.assert_almost_equal( + self.dist(self.breast[:20], axis=0), + np.array([[0., 0.10239274, 0.12786763, 0.13435117, 0.15580385, 0.27429811, 0.21006195, 0.24072005, 0.42847752], + [0.10239274, 0., 0.01695375, 0.10313851, 0.1138925, 0.16978203, 0.1155948, 0.08043531, 0.43326547], + [0.12786763, 0.01695375, 0., 0.16049178, 0.13692762, 0.21784201, 0.11607395, 0.06493949, 0.46590168], + [0.13435117, 0.10313851, 0.16049178, 0., 0.07181648, 0.15585667, 0.13891172, 0.21622332, 0.37404826], + [0.15580385, 0.1138925, 0.13692762, 0.07181648, 0., 0.16301705, 0.17324382, 0.21452448, 0.42283252], + [0.27429811, 0.16978203, 0.21784201, 0.15585667, 0.16301705, 0., 0.25512861, 0.29560909, 0.42766076], + [0.21006195, 0.1155948, 0.11607395, 0.13891172, 0.17324382, 0.25512861, 0., 0.14419442, 0.57976119], + [0.24072005, 0.08043531, 0.06493949, 0.21622332, 0.21452448, 0.29560909, 0.14419442, 0., 0.45930368], + [0.42847752, 0.43326547, 0.46590168, 0.37404826, 0.42283252, 0.42766076, 0.57976119, 0.45930368, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[:4]), + np.array([[0., 0.48462294, 0.10133593, 0.5016744], + [0.48462294, 0., 0.32783865, 0.57317387], + [0.10133593, 0.32783865, 0., 0.63789635]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2], self.breast[:3]), + np.array([[0.10133593, 0.32783865, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[2]), + np.array([[0.10133593], + [0.32783865], + [0.]])) + + def test_pearsonr_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0].x, self.breast[1].x, axis=1), + np.array([[0.48462293898088876]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2].X), + np.array([[0., 0.48462294], + [0.48462294, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2].x, self.breast[:3].X), + np.array([[0.10133593, 0.32783865, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3].X, self.breast[2].x), + np.array([[0.10133593], + [0.32783865], + [0.]])) + + def test_corrcoef2(self): + # Test that _corrcoef2 returns the same result that np.corrcoef would + n, m = tuple(np.random.randint(2, 5, size=2)) + mean = np.random.uniform(-1, 1, size=m) + cov = np.random.uniform(0, 1./m, size=(m, m)) + cov = (cov + cov.T) / 2 + cov.flat[::m + 1] = 1.0 + X1 = np.random.multivariate_normal(mean, cov, size=n) + X2 = np.random.multivariate_normal(mean, cov, size=n) + expected = np.corrcoef(X1, X2, rowvar=True)[:n, n:] + np.testing.assert_almost_equal( + _corrcoef2(X1, X2, axis=1), + expected, + decimal=9 + ) + + expected = np.corrcoef(X1, X2, rowvar=False)[:m, m:] + np.testing.assert_almost_equal( + _corrcoef2(X1, X2, axis=0), + expected, + decimal=9, + ) + + with self.assertRaises(ValueError): + _corrcoef2(X1, X2, axis=10) + + +# noinspection PyTypeChecker +class TestPearsonRAbsolute(TestCase): + @classmethod + def setUpClass(cls): + cls.breast = Table(test_filename( + "datasets/breast-cancer-wisconsin.tab")) + cls.dist = PearsonRAbsolute + + def test_pearsonrabsolute_distance_one_example(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0]), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[0], axis=1), + np.array([[0]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1]), + np.array([[0.48462293898088876]])) + np.testing.assert_almost_equal( + self.dist(self.breast[0], self.breast[1], axis=1), + np.array([[0.48462293898088876]])) + + def test_pearsonrabsolute_distance_many_examples(self): + np.testing.assert_almost_equal( + self.dist(self.breast[:2]), + np.array([[0., 0.48462294], + [0.48462294, 0.]])) + # pylint: disable=line-too-long + # Because it looks better + np.testing.assert_almost_equal( + self.dist(self.breast[:20], axis=0), + np.array([[0., 0.10239274, 0.12786763, 0.13435117, 0.15580385, 0.27429811, 0.21006195, 0.24072005, 0.42847752], + [0.10239274, 0., 0.01695375, 0.10313851, 0.1138925, 0.16978203, 0.1155948, 0.08043531, 0.43326547], + [0.12786763, 0.01695375, 0., 0.16049178, 0.13692762, 0.21784201, 0.11607395, 0.06493949, 0.46590168], + [0.13435117, 0.10313851, 0.16049178, 0., 0.07181648, 0.15585667, 0.13891172, 0.21622332, 0.37404826], + [0.15580385, 0.1138925, 0.13692762, 0.07181648, 0., 0.16301705, 0.17324382, 0.21452448, 0.42283252], + [0.27429811, 0.16978203, 0.21784201, 0.15585667, 0.16301705, 0., 0.25512861, 0.29560909, 0.42766076], + [0.21006195, 0.1155948, 0.11607395, 0.13891172, 0.17324382, 0.25512861, 0., 0.14419442, 0.42023881], + [0.24072005, 0.08043531, 0.06493949, 0.21622332, 0.21452448, 0.29560909, 0.14419442, 0., 0.45930368], + [0.42847752, 0.43326547, 0.46590168, 0.37404826, 0.42283252, 0.42766076, 0.42023881, 0.45930368, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:3], self.breast[:4]), + np.array([[0., 0.48462294, 0.10133593, 0.4983256], + [0.48462294, 0., 0.32783865, 0.42682613], + [0.10133593, 0.32783865, 0., 0.36210365]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2], self.breast[:3]), + np.array([[0.10133593, 0.32783865, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2], self.breast[3]), + np.array([[0.4983256], + [0.42682613]])) + + def test_pearsonrabsolute_distance_numpy(self): + np.testing.assert_almost_equal( + self.dist(self.breast[0].x, self.breast[1].x, axis=1), + np.array([[0.48462293898088876]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2].X), + np.array([[0., 0.48462294], + [0.48462294, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[2].x, self.breast[:3].X), + np.array([[0.10133593, 0.32783865, 0.]])) + np.testing.assert_almost_equal( + self.dist(self.breast[:2].X, self.breast[3].x), + np.array([[0.4983256], + [0.42682613]])) + + +# noinspection PyTypeChecker +# Pylint doesn't get magic __new__ operators +# pylint: disable=not-callable +class TestMahalanobis(TestCase): + def setUp(self): + self.n, self.m = 10, 5 + self.x = np.random.rand(self.n, self.m) + self.x1 = np.random.rand(self.m) + self.x2 = np.random.rand(self.m) + + def test_correctness(self): + mah = MahalanobisDistance(self.x) + d = scipy.spatial.distance.pdist(self.x, 'mahalanobis') + d = scipy.spatial.distance.squareform(d) + for i in range(self.n): + for j in range(self.n): + self.assertAlmostEqual(d[i][j], mah(self.x[i], self.x[j]), + delta=1e-5) + + def test_attributes(self): + metric = MahalanobisDistance(self.x) + self.assertEqual(metric(self.x[0], self.x[1]).shape, (1, 1)) + self.assertEqual(metric(self.x).shape, (self.n, self.n)) + self.assertEqual(metric(self.x[0:3], self.x[5:7]).shape, (3, 2)) + self.assertEqual(metric(self.x1, self.x2).shape, (1, 1)) + metric(self.x, impute=True) + metric(self.x[:-1, :]) + self.assertRaises(ValueError, metric, self.x[:, :-1]) + self.assertRaises(ValueError, metric, self.x1[:-1], self.x2) + self.assertRaises(ValueError, metric, self.x1, self.x2[:-1]) + self.assertRaises(ValueError, metric, self.x.T) + + def test_iris(self): + tab = Table('iris') + metric = MahalanobisDistance(tab) + self.assertEqual(metric(tab).shape, (150, 150)) + self.assertEqual(metric(tab[0], tab[1]).shape, (1, 1)) + + def test_dimensions(self): + x = Table('iris')[:20].X + xt = Table('iris')[:20].X.T + mah = MahalanobisDistance(x) + mah(x[0], x[1]) + mah = MahalanobisDistance(xt) + mah(xt[0], xt[1]) + + +class TestBhattacharyya(TestCase): + + @classmethod + def setUpClass(cls): + cls.dist = Bhattacharyya + + def test_dense_array(self): + #Also checks normalization + data = Table('iris') + true_out = np.array([[0, 4.48049499e-04, 2.07117086e-05], + [4.48049499e-04, 0, 3.65052724e-04], + [2.07117086e-05, 3.65052724e-04, 0]]) + np.testing.assert_array_almost_equal(self.dist(data.X[:3]), true_out) + + def test_sparse_array(self): + data = csr_matrix([[0.5, 0.5], [0, 0.5]]) + self.assertAlmostEqual(self.dist(data[0], data[1]), 0.3465735902799726, delta=1e-5) + + def test_columns(self): + data = np.array([[0.5, 0.2], [0.5, 0.8]]) + true_out = np.array([[0, 0.05268025782891318], + [0.05268025782891318, 0]]) + np.testing.assert_array_almost_equal(self.dist(data, axis=0), true_out) + + def test_negative_input(self): + a = np.array([0, np.nan]) + b = np.array([1, 1]) + self.assertRaises(ValueError, self.dist, a, b) + a[1] = -1 + self.assertRaises(ValueError, self.dist, a, b) + a = csr_matrix(a) + b = csr_matrix(b) + self.assertRaises(ValueError, self.dist, a, b) + + +class TestDistances(TestCase): + @classmethod + def setUpClass(cls): + cls.test5 = Table(test_filename('datasets/test5.tab')) + + def test_preprocess(self): + domain = Domain([ContinuousVariable("c"), + DiscreteVariable("d", values=['a', 'b'])], + [DiscreteVariable("cls", values=['e', 'f'])], + [StringVariable("m")]) + table = Table.from_list(domain, [[1, 'a', 'e', 'm1'], + [2, 'b', 'f', 'm2']]) + new_table = _preprocess(table) + np.testing.assert_equal(new_table.X, table.X[:, 0].reshape(2, 1)) + np.testing.assert_equal(new_table.Y, table.Y) + np.testing.assert_equal(new_table.metas, table.metas) + self.assertEqual([a.name for a in new_table.domain.attributes], + [a.name for a in table.domain.attributes + if a.is_continuous]) + self.assertEqual(new_table.domain.class_vars, table.domain.class_vars) + self.assertEqual(new_table.domain.metas, table.domain.metas) + + def test_preprocess_multiclass(self): + table = self.test5 + new_table = _preprocess(table) + np.testing.assert_equal(new_table.Y, table.Y) + self.assertEqual([a.name for a in new_table.domain.attributes], + [a.name for a in table.domain.attributes if + a.is_continuous and not all(np.isnan(table[:, a].X))]) + self.assertEqual(new_table.domain.class_vars, table.domain.class_vars) + + def test_preprocess_impute(self): + new_table = _preprocess(self.test5) + self.assertFalse(np.isnan(new_table.X).any()) + + def test_distance_to_instance(self): + iris = Table('iris') + inst = Instance(iris.domain, np.concatenate((iris[1].x, iris[1].y))) + self.assertEqual(Euclidean(iris[1], inst), 0) + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/test_distribution.py b/pyminer2/tests/test_distribution.py new file mode 100644 index 0000000000000000000000000000000000000000..cda3b0e77753cf434d65275b21e8b26a78dc1c85 --- /dev/null +++ b/pyminer2/tests/test_distribution.py @@ -0,0 +1,544 @@ +# Test methods with long descriptive names can omit docstrings +# Test internal methods +# pylint: disable=missing-docstring, protected-access + +import unittest +from unittest.mock import Mock +import warnings + +import numpy as np +import scipy.sparse as sp + +from Orange.statistics import distribution +from Orange import data +from Orange.tests import test_filename + + +def assert_dist_equal(dist, expected): + np.testing.assert_array_equal(np.asarray(dist), expected) + + +def assert_dist_almost_equal(dist, expected): + np.testing.assert_almost_equal(np.asarray(dist), expected) + + +class TestDiscreteDistribution(unittest.TestCase): + def setUp(self): + self.freqs = [4.0, 20.0, 13.0, 8.0, 10.0, 41.0, 5.0] + s = sum(self.freqs) + self.rfreqs = [x/s for x in self.freqs] + + self.data = data.Table.from_numpy( + data.Domain( + attributes=[ + data.DiscreteVariable('rgb', values=['r', 'g', 'b', 'a']), + data.DiscreteVariable('num', values=['1', '2', '3'], ordered=True), + ] + ), + X=np.array([ + [0, 2, 0, 1, 1, 0, np.nan, 1], + [0, 2, 0, np.nan, 1, 2, np.nan, 1], + ]).T + ) + self.rgb, self.num = distribution.get_distributions(self.data) + + def test_from_table(self): + d = data.Table("zoo") + disc = distribution.Discrete(d, "type") + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc.variable, d.domain["type"]) + self.assertEqual(disc.unknowns, 0) + assert_dist_equal(disc, self.freqs) + + disc2 = distribution.Discrete(d, d.domain.class_var) + self.assertIsInstance(disc2, np.ndarray) + self.assertIs(disc2.variable, d.domain.class_var) + self.assertEqual(disc, disc2) + + disc3 = distribution.Discrete(d, len(d.domain.attributes)) + self.assertIsInstance(disc3, np.ndarray) + self.assertIs(disc3.variable, d.domain.class_var) + self.assertEqual(disc, disc3) + + disc5 = distribution.class_distribution(d) + self.assertIsInstance(disc5, np.ndarray) + self.assertIs(disc5.variable, d.domain.class_var) + self.assertEqual(disc, disc5) + + def test_construction(self): + d = data.Table("zoo") + + disc = distribution.Discrete(d, "type") + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc.variable, d.domain["type"]) + self.assertEqual(disc.unknowns, 0) + self.assertIs(disc.variable, d.domain.class_var) + + disc7 = distribution.Discrete(self.freqs) + self.assertIsInstance(disc, np.ndarray) + self.assertIsNone(disc7.variable) + self.assertEqual(disc7.unknowns, 0) + self.assertEqual(disc, disc7) + + disc1 = distribution.Discrete(None, d.domain.class_var) + self.assertIsInstance(disc1, np.ndarray) + self.assertIs(disc1.variable, d.domain.class_var) + self.assertEqual(disc.unknowns, 0) + assert_dist_equal(disc1, [0]*len(d.domain.class_var.values)) + + def test_fallback(self): + d = data.Table("zoo") + default = distribution.Discrete(d, "type") + + d._compute_distributions = Mock(side_effect=NotImplementedError) + fallback = distribution.Discrete(d, "type") + + np.testing.assert_almost_equal( + np.asarray(fallback), np.asarray(default)) + np.testing.assert_almost_equal(fallback.unknowns, default.unknowns) + + def test_fallback_with_weights_and_nan(self): + d = data.Table("zoo") + d.set_weights(np.random.uniform(0., 1., size=len(d))) + d.Y[::10] = np.nan + + default = distribution.Discrete(d, "type") + d._compute_distributions = Mock(side_effect=NotImplementedError) + fallback = distribution.Discrete(d, "type") + + np.testing.assert_almost_equal( + np.asarray(fallback), np.asarray(default)) + np.testing.assert_almost_equal(fallback.unknowns, default.unknowns) + + def test_equality(self): + d = data.Table("zoo") + d1 = distribution.Discrete(d, 0) + d2 = distribution.Discrete(d, 0) + d3 = distribution.Discrete(d, 1) + + self.assertEqual(d1, d1) + self.assertEqual(d1, d2) + self.assertNotEqual(d1, d3) + + def test_indexing(self): + d = data.Table("zoo") + indamphibian = d.domain.class_var.to_val("amphibian") + + disc = distribution.class_distribution(d) + + self.assertEqual(len(disc), len(d.domain.class_var.values)) + + self.assertEqual(disc["mammal"], 41) + self.assertEqual(disc[indamphibian], 4) + + disc["mammal"] = 100 + self.assertEqual(disc[d.domain.class_var.to_val("mammal")], 100) + + disc[indamphibian] = 33 + self.assertEqual(disc["amphibian"], 33) + + disc = distribution.class_distribution(d) + self.assertEqual(list(disc), self.freqs) + + def test_hash(self): + d = data.Table("zoo") + disc = distribution.Discrete(d, "type") + + disc2 = distribution.Discrete(d, d.domain.class_var) + self.assertEqual(hash(disc), hash(disc2)) + + disc2[0] += 1 + self.assertNotEqual(hash(disc), hash(disc2)) + + disc2[0] -= 1 + self.assertEqual(hash(disc), hash(disc2)) + + disc2.unknowns += 1 + self.assertNotEqual(hash(disc), hash(disc2)) + + def test_add(self): + d = data.Table("zoo") + disc = distribution.Discrete(d, "type") + + disc += [1, 2, 3, 4, 5, 6, 7] + self.assertEqual(disc, [5.0, 22.0, 16.0, 12.0, 15.0, 47.0, 12.0]) + + disc2 = distribution.Discrete(d, d.domain.class_var) + + disc3 = disc - disc2 + self.assertEqual(disc3, list(range(1, 8))) + + disc3 *= 2 + self.assertEqual(disc3, [2*x for x in range(1, 8)]) + + def test_normalize(self): + d = data.Table("zoo") + disc = distribution.Discrete(d, "type") + disc.normalize() + self.assertEqual(disc, self.rfreqs) + disc.normalize() + self.assertEqual(disc, self.rfreqs) + + disc1 = distribution.Discrete(None, d.domain.class_var) + disc1.normalize() + v = len(d.domain.class_var.values) + assert_dist_almost_equal(disc1, [1/v]*v) + + def test_modus(self): + d = data.Table("zoo") + disc = distribution.Discrete(d, "type") + self.assertEqual(str(disc.modus()), "mammal") + + def test_sample(self): + ans = self.num.sample((500, 2), replace=True) + np.testing.assert_equal(np.unique(ans), [0, 1, 2]) + + # Check that samping a single value works too + self.assertIn(self.num.sample(), [0, 1, 2]) + + def test_min_max(self): + # Min and max don't make sense in the context of nominal variables + self.assertEqual(self.rgb.min(), None) + self.assertEqual(self.rgb.max(), None) + # Min and max should work for ordinal variables + self.assertEqual(self.num.min(), '1') + self.assertEqual(self.num.max(), '3') + + def test_array_with_unknowns(self): + d = data.Table("zoo") + d.Y[0] = np.nan + disc = distribution.Discrete(d, "type") + self.assertIsInstance(disc, np.ndarray) + self.assertEqual(disc.unknowns, 1) + true_freq = [4., 20., 13., 8., 10., 40., 5.] + assert_dist_equal(disc, true_freq) + np.testing.assert_array_equal(disc.array_with_unknowns, + np.append(true_freq, 1)) + + +class TestContinuousDistribution(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = data.Table("iris") + + cls.data = data.Table.from_numpy( + data.Domain( + attributes=[ + data.ContinuousVariable('n1'), + data.ContinuousVariable('n2'), + ] + ), + X=np.array([range(10), [1, 1, 1, 5, 5, 8, 9, np.nan, 9, 9]]).T + ) + cls.n1, cls.n2 = distribution.get_distributions(cls.data) + + def setUp(self): + self.freqs = np.array([(1.0, 1), (1.1, 1), (1.2, 2), (1.3, 7), (1.4, 12), + (1.5, 14), (1.6, 7), (1.7, 4), (1.9, 2), (3.0, 1), + (3.3, 2), (3.5, 2), (3.6, 1), (3.7, 1), (3.8, 1), + (3.9, 3), (4.0, 5), (4.1, 3), (4.2, 4), (4.3, 2), + (4.4, 4), (4.5, 8), (4.6, 3), (4.7, 5), (4.8, 4), + (4.9, 5), (5.0, 4), (5.1, 8), (5.2, 2), (5.3, 2), + (5.4, 2), (5.5, 3), (5.6, 6), (5.7, 3), (5.8, 3), + (5.9, 2), (6.0, 2), (6.1, 3), (6.3, 1), (6.4, 1), + (6.6, 1), (6.7, 2), (6.9, 1)]).T + + def test_from_table(self): + d = self.iris + petal_length = d.columns.petal_length + + for attr in ["petal length", d.domain[2], 2]: + disc = distribution.Continuous(d, attr) + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc.variable, petal_length) + self.assertEqual(disc.unknowns, 0) + assert_dist_almost_equal(disc, self.freqs) + + def test_construction(self): + d = self.iris + petal_length = d.columns.petal_length + + disc = distribution.Continuous(d, "petal length") + + disc7 = distribution.Continuous(self.freqs) + self.assertIsInstance(disc, np.ndarray) + self.assertIsNone(disc7.variable) + self.assertEqual(disc7.unknowns, 0) + self.assertEqual(disc, disc7) + + disc7 = distribution.Continuous(self.freqs, petal_length) + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc7.variable, petal_length) + self.assertEqual(disc7.unknowns, 0) + self.assertEqual(disc, disc7) + + disc1 = distribution.Continuous(10, petal_length) + self.assertIsInstance(disc1, np.ndarray) + self.assertIs(disc7.variable, petal_length) + self.assertEqual(disc7.unknowns, 0) + assert_dist_equal(disc1, np.zeros((2, 10))) + + dd = [list(range(5)), [1, 1, 2, 5, 1]] + disc2 = distribution.Continuous(dd) + self.assertIsInstance(disc2, np.ndarray) + self.assertIsNone(disc2.variable) + self.assertEqual(disc2.unknowns, 0) + assert_dist_equal(disc2, dd) + + def test_hash(self): + d = self.iris + petal_length = d.columns.petal_length + + disc = distribution.Continuous(d, "petal length") + disc2 = distribution.Continuous(d, petal_length) + self.assertEqual(hash(disc), hash(disc2)) + + disc2[0, 0] += 1 + self.assertNotEqual(hash(disc), hash(disc2)) + + disc2[0, 0] -= 1 + self.assertEqual(hash(disc), hash(disc2)) + + disc2.unknowns += 1 + self.assertNotEqual(hash(disc), hash(disc2)) + + def test_normalize(self): + d = self.iris + petal_length = d.columns.petal_length + + disc = distribution.Continuous(d, "petal length") + + assert_dist_equal(disc, self.freqs) + disc.normalize() + self.freqs[1, :] /= 150 + assert_dist_equal(disc, self.freqs) + + disc1 = distribution.Continuous(10, petal_length) + disc1.normalize() + f = np.zeros((2, 10)) + f[1, :] = 0.1 + assert_dist_equal(disc1, f) + + def test_modus(self): + disc = distribution.Continuous([list(range(5)), [1, 1, 2, 5, 1]]) + self.assertEqual(disc.modus(), 3) + + def test_random(self): + d = self.iris + + disc = distribution.Continuous(d, "petal length") + ans = set() + for i in range(1000): + v = disc.sample() + self.assertIn(v, self.freqs) + ans.add(v) + self.assertGreater(len(ans), 10) + + def test_min_max(self): + self.assertEqual(self.n1.min(), 0) + self.assertFalse(isinstance(self.n1.min(), distribution.Continuous)) + self.assertEqual(self.n1.max(), 9) + self.assertFalse(isinstance(self.n1.max(), distribution.Continuous)) + + +class TestClassDistribution(unittest.TestCase): + def test_class_distribution(self): + d = data.Table("zoo") + disc = distribution.class_distribution(d) + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc.variable, d.domain["type"]) + self.assertEqual(disc.unknowns, 0) + assert_dist_equal(disc, [4.0, 20.0, 13.0, 8.0, 10.0, 41.0, 5.0]) + + def test_multiple_target_variables(self): + d = data.Table.from_numpy( + data.Domain( + attributes=[data.ContinuousVariable('n1')], + class_vars=[ + data.DiscreteVariable('c1', values=['r', 'g', 'b', 'a']), + data.DiscreteVariable('c2', values=['r', 'g', 'b', 'a']), + data.DiscreteVariable('c3', values=['r', 'g', 'b', 'a']), + ] + ), + X=np.array([range(5)]).T, + Y=np.array([ + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + ]).T + ) + dists = distribution.class_distribution(d) + self.assertEqual(len(dists), 3) + self.assertTrue(all(isinstance(dist, distribution.Discrete) for dist in dists)) + + +class TestGetDistribution(unittest.TestCase): + def test_get_distribution(self): + d = data.Table("iris") + cls = d.domain.class_var + disc = distribution.get_distribution(d, cls) + self.assertIsInstance(disc, np.ndarray) + self.assertIs(disc.variable, cls) + self.assertEqual(disc.unknowns, 0) + assert_dist_equal(disc, [50, 50, 50]) + + petal_length = d.columns.petal_length + freqs = np.array([(1.0, 1), (1.1, 1), (1.2, 2), (1.3, 7), (1.4, 12), + (1.5, 14), (1.6, 7), (1.7, 4), (1.9, 2), (3.0, 1), + (3.3, 2), (3.5, 2), (3.6, 1), (3.7, 1), (3.8, 1), + (3.9, 3), (4.0, 5), (4.1, 3), (4.2, 4), (4.3, 2), + (4.4, 4), (4.5, 8), (4.6, 3), (4.7, 5), (4.8, 4), + (4.9, 5), (5.0, 4), (5.1, 8), (5.2, 2), (5.3, 2), + (5.4, 2), (5.5, 3), (5.6, 6), (5.7, 3), (5.8, 3), + (5.9, 2), (6.0, 2), (6.1, 3), (6.3, 1), (6.4, 1), + (6.6, 1), (6.7, 2), (6.9, 1)]).T + disc = distribution.get_distribution(d, petal_length) + assert_dist_equal(disc, freqs) + + +class TestDomainDistribution(unittest.TestCase): + def test_get_distributions(self): + d = data.Table("iris") + ddist = distribution.get_distributions(d) + + self.assertEqual(len(ddist), 5) + for i in range(4): + self.assertIsInstance(ddist[i], distribution.Continuous) + self.assertIsInstance(ddist[-1], distribution.Discrete) + + freqs = np.array([(1.0, 1), (1.1, 1), (1.2, 2), (1.3, 7), (1.4, 12), + (1.5, 14), (1.6, 7), (1.7, 4), (1.9, 2), (3.0, 1), + (3.3, 2), (3.5, 2), (3.6, 1), (3.7, 1), (3.8, 1), + (3.9, 3), (4.0, 5), (4.1, 3), (4.2, 4), (4.3, 2), + (4.4, 4), (4.5, 8), (4.6, 3), (4.7, 5), (4.8, 4), + (4.9, 5), (5.0, 4), (5.1, 8), (5.2, 2), (5.3, 2), + (5.4, 2), (5.5, 3), (5.6, 6), (5.7, 3), (5.8, 3), + (5.9, 2), (6.0, 2), (6.1, 3), (6.3, 1), (6.4, 1), + (6.6, 1), (6.7, 2), (6.9, 1)]).T + assert_dist_equal(ddist[2], freqs) + assert_dist_equal(ddist[-1], [50, 50, 50]) + + def test_sparse_get_distributions(self): + def assert_dist_and_unknowns(computed, goal_dist): + nonlocal d + goal_dist = np.array(goal_dist) + sum_dist = np.sum(goal_dist[1, :] if goal_dist.ndim == 2 else goal_dist) + n_all = np.sum(d.W) if d.has_weights() else len(d) + + assert_dist_almost_equal(computed, goal_dist) + self.assertEqual(computed.unknowns, n_all - sum_dist) + + domain = data.Domain( + [data.DiscreteVariable("d%i" % i, values=list("abc")) for i in range(10)] + + [data.ContinuousVariable("c%i" % i) for i in range(10)]) + + # pylint: disable=bad-whitespace + X = sp.csr_matrix( + # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + # -------------------------------------------------------------------------------- + [[0, 2, 0, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, np.nan, 2, 0], + [0, 0, 1, 1, np.nan, np.nan, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1, np.nan, 0, 0], + [0, 0, 0, 1, 0, 2, np.nan, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 0]] + ) + warnings.filterwarnings("ignore", ".*", sp.SparseEfficiencyWarning) + X[0, 0] = 0 + + d = data.Table.from_numpy(domain, X) + ddist = distribution.get_distributions(d) + + self.assertEqual(len(ddist), 20) + zeros = [5, 0, 0] + assert_dist_and_unknowns(ddist[0], zeros) + assert_dist_and_unknowns(ddist[1], [4, 0, 1]) + assert_dist_and_unknowns(ddist[2], [3, 1, 1]) + assert_dist_and_unknowns(ddist[3], [2, 2, 1]) + assert_dist_and_unknowns(ddist[4], [3, 1, 0]) + assert_dist_and_unknowns(ddist[5], [2, 1, 1]) + assert_dist_and_unknowns(ddist[6], [1, 2, 1]) + assert_dist_and_unknowns(ddist[7], zeros) + assert_dist_and_unknowns(ddist[8], [4, 0, 1]) + assert_dist_and_unknowns(ddist[9], [4, 1, 0]) + + zeros = [[0], [5]] + assert_dist_and_unknowns(ddist[10], zeros) + assert_dist_and_unknowns(ddist[11], zeros) + assert_dist_and_unknowns(ddist[12], zeros) + assert_dist_and_unknowns(ddist[13], [[0, 1, 1.1], [3, 1, 1]]) + assert_dist_and_unknowns(ddist[14], [[0, 1, 2], [3, 1, 1]]) + assert_dist_and_unknowns(ddist[15], zeros) + assert_dist_and_unknowns(ddist[16], [[0, 1, 2], [3, 1, 1]]) + assert_dist_and_unknowns(ddist[17], [[0], [3]]) + assert_dist_and_unknowns(ddist[18], [[0, 2], [4, 1]]) + assert_dist_and_unknowns(ddist[19], zeros) + + d.set_weights(np.array([1, 2, 3, 4, 5])) + ddist = distribution.get_distributions(d) + + self.assertEqual(len(ddist), 20) + assert_dist_and_unknowns(ddist[0], [15, 0, 0]) + assert_dist_and_unknowns(ddist[1], [14, 0, 1]) + assert_dist_and_unknowns(ddist[2], [8, 2, 5]) + assert_dist_and_unknowns(ddist[3], [9, 5, 1]) + assert_dist_and_unknowns(ddist[4], [12, 1, 0]) + assert_dist_and_unknowns(ddist[5], [9, 1, 3]) + assert_dist_and_unknowns(ddist[6], [4, 7, 1]) + assert_dist_and_unknowns(ddist[7], [15, 0, 0]) + assert_dist_and_unknowns(ddist[8], [13, 0, 2]) + assert_dist_and_unknowns(ddist[9], [14, 1, 0]) + + zeros = [[0], [15]] + assert_dist_and_unknowns(ddist[10], zeros) + assert_dist_and_unknowns(ddist[11], zeros) + assert_dist_and_unknowns(ddist[12], zeros) + assert_dist_and_unknowns(ddist[13], [[0, 1, 1.1], [9, 1, 5]]) + assert_dist_and_unknowns(ddist[14], [[0, 1, 2], [12, 1, 2]]) + assert_dist_and_unknowns(ddist[15], zeros) + assert_dist_and_unknowns(ddist[16], [[0, 1, 2], [12, 2, 1]]) + assert_dist_and_unknowns(ddist[17], [[0], [12]]) + assert_dist_and_unknowns(ddist[18], [[0, 2], [14, 1]]) + assert_dist_and_unknowns(ddist[19], zeros) + + def test_compute_distributions_metas(self): + d = data.Table(test_filename("datasets/test9.tab")) + variable = d.domain[-2] + dist, _ = d._compute_distributions([variable])[0] + assert_dist_equal(dist, [3, 3, 2]) + # repeat with nan values + assert d.metas.dtype.kind == "O" + assert d.metas[0, 1] == 0 + d.metas[0, 1] = np.nan + dist, nanc = d._compute_distributions([variable])[0] + assert_dist_equal(dist, [2, 3, 2]) + self.assertEqual(nanc, 1) + + +class TestContinuous(unittest.TestCase): + def test_mean(self): + # pylint: disable=bad-whitespace + x = np.array([[0, 5, 10], + [9, 0, 1]]) + dist = distribution.Continuous(x) + + self.assertEqual(dist.mean(), np.mean(([0] * 9) + [10])) + + def test_variance(self): + # pylint: disable=bad-whitespace + x = np.array([[0, 5, 10], + [9, 0, 1]]) + dist = distribution.Continuous(x) + + self.assertEqual(dist.variance(), np.var(([0] * 9) + [10])) + + def test_standard_deviation(self): + # pylint: disable=bad-whitespace + x = np.array([[0, 5, 10], + [9, 0, 1]]) + dist = distribution.Continuous(x) + + self.assertEqual(dist.standard_deviation(), np.std(([0] * 9) + [10])) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_doctest.py b/pyminer2/tests/test_doctest.py new file mode 100644 index 0000000000000000000000000000000000000000..624291ef96862192a672f3aabbc6fb9427b321c6 --- /dev/null +++ b/pyminer2/tests/test_doctest.py @@ -0,0 +1,88 @@ +import sys +import os +import unittest +from doctest import DocTestSuite, ELLIPSIS, NORMALIZE_WHITESPACE +from distutils.version import LooseVersion + +import numpy + +SKIP_DIRS = ( + # Skip modules which import and initialize stuff that require QApplication + 'Orange/widgets', + 'Orange/canvas', + # Skip because we don't want Orange.datasets as a module (yet) + 'Orange/datasets/' +) + +if sys.platform == "win32": + # convert to platform native path component separators + SKIP_DIRS = tuple(os.path.normpath(p) for p in SKIP_DIRS) + + +def find_modules(package): + """Return a recursive list of submodules for a given package""" + from os import path, walk + module = path.dirname(getattr(package, '__file__', package)) + parent = path.dirname(module) + files = (path.join(dir, file)[len(parent) + 1:-3] + for dir, dirs, files in walk(module) + for file in files + if file.endswith('.py')) + files = (f for f in files if not f.startswith(SKIP_DIRS)) + files = (f.replace(path.sep, '.') for f in files) + return files + + +class Context(dict): + """ + Execution context that retains the changes the tests make. Preferably + use one per module to obtain nice "literate" modules that "follow along". + + In other words, directly the opposite of: + https://docs.python.org/3/library/doctest.html#what-s-the-execution-context + + By popular demand: + http://stackoverflow.com/questions/13106118/object-reuse-in-python-doctest/13106793#13106793 + http://stackoverflow.com/questions/3286658/embedding-test-code-or-data-within-doctest-strings + """ + def copy(self): + return self + + def clear(self): + pass + + +def suite(package): + """Assemble test suite for doctests in path (recursively)""" + from importlib import import_module + # numpy 1.14 changed array str/repr (NORMALIZE_WHITESPACE does not + # handle this). When 1.15 is released update all docstrings and skip the + # tests for < 1.14. + npversion = LooseVersion(numpy.__version__) + if npversion >= LooseVersion("1.14"): + def setUp(test): + raise unittest.SkipTest("Skip doctest on numpy >= 1.14.0") + else: + def setUp(test): + pass + + for module in find_modules(package.__file__): + try: + module = import_module(module) + yield DocTestSuite(module, + globs=Context(module.__dict__.copy()), + optionflags=ELLIPSIS | NORMALIZE_WHITESPACE, + setUp=setUp) + except ValueError: + pass # No doctests in module + except ImportError: + import warnings + warnings.warn('Unimportable module: {}'.format(module)) + + +def load_tests(loader, tests, ignore): + # This follows the load_tests protocol + # https://docs.python.org/3/library/unittest.html#load-tests-protocol + import Orange + tests.addTests(suite(Orange)) + return tests diff --git a/pyminer2/tests/test_domain.py b/pyminer2/tests/test_domain.py new file mode 100644 index 0000000000000000000000000000000000000000..9501a6596d15a4405f98c44580d582bbae112034 --- /dev/null +++ b/pyminer2/tests/test_domain.py @@ -0,0 +1,558 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import warnings +from time import time +from numbers import Real +from itertools import starmap, chain +import unittest +import pickle + +import numpy as np +from numpy.testing import assert_array_equal + +from Orange.data import ( + ContinuousVariable, DiscreteVariable, StringVariable, TimeVariable, + Variable, Domain, Table, DomainConversion) +from Orange.data.domain import filter_visible +from Orange.preprocess import Continuize, Impute +from Orange.tests.base import create_pickling_tests +from Orange.util import OrangeDeprecationWarning + + +def create_domain(*ss): + vars = dict( + age=ContinuousVariable(name="AGE"), + gender=DiscreteVariable(name="Gender", values=["M", "F"]), + incomeA=ContinuousVariable(name="incomeA"), + income=ContinuousVariable(name="income"), + education=DiscreteVariable(name="education", values=["GS", "HS", "C"]), + ssn=StringVariable(name="SSN"), + race=DiscreteVariable(name="race", + values=["White", "Hypsanic", "African", "Other"]), + arrival=TimeVariable("arrival")) + + def map_vars(s): + return [vars[x] for x in s] + return Domain(*[map_vars(s) for s in ss]) + + +PickleDomain = create_pickling_tests( + "PickleDomain", + ("empty_domain", lambda: create_domain([])), + ("with_continuous_variable", lambda: create_domain(["age"])), + ("with_discrete_variable", lambda: create_domain(["gender"])), + ("with_mixed_variables", lambda: create_domain(["age", "gender"])), + ("with_continuous_class", lambda: create_domain(["age", "gender"], ["incomeA"])), + ("with_discrete_class", lambda: create_domain(["age", "gender"], ["education"])), + ("with_multiple_classes", lambda: create_domain(["age", "gender"], + ["incomeA", "education"])), + ("with_metas", lambda: create_domain(["age", "gender"], [], ["ssn"])), + ("with_class_and_metas", lambda: create_domain(["age", "gender"], + ["incomeA", "education"], + ["ssn"])), +) + + +age, gender, incomeA, income, education, ssn, race, arrival = \ + create_domain([], [], + ["age", "gender", "incomeA", "income", "education", "ssn", + "race", "arrival"]).metas + + +class TestDomainInit(unittest.TestCase): + def test_init_class(self): + attributes = (age, gender, income) + d = Domain(attributes, race) + self.assertEqual(d.variables, attributes + (race,)) + self.assertEqual(d.attributes, attributes) + self.assertEqual(d.class_var, race) + self.assertEqual(d.class_vars, (race,)) + self.assertEqual(d.metas, ()) + + def test_init_class_list(self): + attributes = (age, gender, income) + d = Domain(attributes, [race]) + self.assertEqual(d.variables, attributes + (race,)) + self.assertEqual(d.attributes, attributes) + self.assertEqual(d.class_var, race) + self.assertEqual(d.class_vars, (race,)) + self.assertEqual(d.metas, ()) + + def test_init_no_class(self): + attributes = (age, gender, income) + d = Domain(attributes) + self.assertEqual(d.variables, attributes) + self.assertEqual(d.attributes, attributes) + self.assertEqual(d.class_var, None) + self.assertEqual(d.class_vars, ()) + self.assertEqual(d.metas, ()) + + def test_init_no_class_false(self): + attributes = (age, gender, income) + d = Domain(attributes, None) + self.assertEqual(d.variables, attributes) + self.assertEqual(d.attributes, attributes) + self.assertEqual(d.class_var, None) + self.assertEqual(d.class_vars, ()) + self.assertEqual(d.metas, ()) + + def test_init_multi_class(self): + attributes = (age, gender, income) + d = Domain(attributes, (education, race)) + self.assertEqual(d.variables, attributes + (education, race)) + self.assertEqual(d.attributes, attributes) + self.assertIsNone(d.class_var) + self.assertEqual(d.class_vars, (education, race)) + self.assertEqual(d.metas, ()) + + def test_init_source(self): + attributes = (age, gender, income) + d = Domain(attributes, (education, race)) + d2 = Domain(["Gender", 0, income], source=d) + self.assertEqual(d2.variables, (gender, age, income)) + + def test_init_source_class(self): + attributes = (age, gender, income) + d = Domain(attributes, (education, race)) + d2 = Domain(["Gender", 0], "income", source=d) + self.assertEqual(d2.variables, (gender, age, income)) + + def test_init_metas(self): + attributes = (age, gender, income) + metas = (ssn, race) + d = Domain(attributes, race, metas=metas) + self.assertEqual(d.variables, attributes + (race, )) + self.assertEqual(d.attributes, attributes) + self.assertEqual(d.class_var, race) + self.assertEqual(d.class_vars, (race, )) + self.assertEqual(d.metas, metas) + + def test_from_numpy_names(self): + for n_cols, name in [(5, "Feature {}"), + (99, "Feature {:02}"), + (100, "Feature {:03}")]: + d = Domain.from_numpy(np.zeros((1, n_cols))) + self.assertTrue(d.anonymous) + self.assertEqual([var.name for var in d.attributes], + [name.format(i) for i in range(1, n_cols+1)]) + + d = Domain.from_numpy(np.zeros((1, 1))) + self.assertTrue(d.anonymous) + self.assertEqual(d.attributes[0].name, "Feature") + + d = Domain.from_numpy(np.zeros((1, 3)), np.zeros((1, 1)), + np.zeros((1, 100))) + self.assertTrue(d.anonymous) + self.assertEqual([var.name for var in d.attributes], + ["Feature {}".format(i) for i in range(1, 4)]) + self.assertEqual(d.class_var.name, "Target") + self.assertEqual([var.name for var in d.metas], + ["Meta {:03}".format(i) for i in range(1, 101)]) + + def test_from_numpy_dimensions(self): + for dimension in [[5], [5, 1]]: + d = Domain.from_numpy(np.zeros((1, 1)), np.zeros(dimension)) + self.assertTrue(d.anonymous) + self.assertEqual(len(d.class_vars), 1) + + self.assertRaises(ValueError, Domain.from_numpy, np.zeros(2)) + self.assertRaises(ValueError, Domain.from_numpy, np.zeros((2, 2, 2))) + self.assertRaises(ValueError, Domain.from_numpy, np.zeros((2, 2)), np.zeros((2, 2, 2))) + + def test_from_numpy_values(self): + for aran_min, aran_max, vartype in [(1, 3, ContinuousVariable), + (0, 2, DiscreteVariable), + (18, 23, ContinuousVariable)]: + n_rows, n_cols, = aran_max - aran_min, 1 + d = Domain.from_numpy(np.zeros((1, 1)), + np.arange(aran_min, aran_max).reshape(n_rows, n_cols)) + self.assertTrue(d.anonymous) + self.assertIsInstance(d.class_var, vartype) + if isinstance(vartype, DiscreteVariable): + self.assertEqual(d.class_var.values, ["v{}".format(i) for i in range(1, 3)]) + + def test_wrong_vartypes(self): + attributes = (age, gender, income) + for args in ((attributes, ssn), + (attributes + (ssn,)), + ((ssn, ) + attributes)): + with self.assertRaises(TypeError): + Domain(*args) + + def test_wrong_vartypes_w_source(self): + d = Domain((age, gender), metas=(ssn,)) + with self.assertRaises(TypeError): + Domain(-1, source=d) + + def test_wrong_types(self): + with self.assertRaises(TypeError): + Domain((age, [])) + with self.assertRaises(TypeError): + Domain((age, "income")) + with self.assertRaises(TypeError): + Domain(([], age)) + with self.assertRaises(TypeError): + Domain(("income", age)) + with self.assertRaises(TypeError): + Domain((age,), self) + with self.assertRaises(TypeError): + Domain((age,), metas=("income",)) + + def test_get_item(self): + d = Domain((age, gender, income), metas=(ssn, race)) + for idx, var in [(age, age), + ("AGE", age), + (0, age), + (income, income), + ("income", income), + (2, income), + (ssn, ssn), + ("SSN", ssn), + (-1, ssn), + (-2, race)]: + self.assertEqual(d[idx], var) + + def test_index(self): + d = Domain((age, gender, income), metas=(ssn, race)) + for idx, var in [(age, 0), + ("AGE", 0), + (0, 0), + (np.int_(0), 0), + (income, 2), + ("income", 2), + (2, 2), + (np.int_(2), 2), + (ssn, -1), + ("SSN", -1), + (-1, -1), + (np.int_(-1), -1), + (-2, -2), (np.int_(-2), -2)]: + self.assertEqual(d.index(idx), var) + + def test_get_item_slices(self): + d = Domain((age, gender, income, race), metas=(ssn, race)) + self.assertEqual(d[:2], (age, gender)) + self.assertEqual(d[1:3], (gender, income)) + self.assertEqual(d[2:], (income, race)) + + def test_get_item_error(self): + d = Domain((age, gender, income), metas=(ssn, race)) + for idx in (3, -3, incomeA, "no_such_thing"): + with self.assertRaises(KeyError): + _ = d[idx] + + with self.assertRaises(TypeError): + _ = d[[2]] + + def test_index_error(self): + d = Domain((age, gender, income), metas=(ssn, race)) + for idx in (3, np.int(3), -3, np.int(-3), incomeA, "no_such_thing"): + with self.assertRaises(ValueError): + d.index(idx) + + with self.assertRaises(TypeError): + d.index([2]) + + def test_contains(self): + d = Domain((age, gender, income), metas=(ssn,)) + for var in ["AGE", age, 0, np.int_(0), + "income", income, 2, np.int_(2), + "SSN", ssn, -1, np.int_(-1)]: + self.assertIn(var, d) + + for var in ["no_such_thing", race, 3, np.int_(3), -2, np.int_(-2)]: + self.assertNotIn(var, d) + + with self.assertRaises(TypeError): + {} in d + with self.assertRaises(TypeError): + [] in d + + def test_iter(self): + with warnings.catch_warnings(record=True): + warnings.simplefilter("error") + + d = Domain((age, gender, income), metas=(ssn,)) + with self.assertRaises(OrangeDeprecationWarning): + list(d) + + warnings.simplefilter("ignore") + self.assertEqual([var for var in d], [age, gender, income]) + + d = Domain((age, ), metas=(ssn,)) + self.assertEqual([var for var in d], [age]) + + d = Domain((), metas=(ssn,)) + self.assertEqual([var for var in d], []) + + def test_str(self): + cases = ( + (((),), "[]"), + (((age,),), "[AGE]"), + (((), age), "[ | AGE]"), + (((gender,), age), "[Gender | AGE]"), + (((gender, income), None), "[Gender, income]"), + (((gender, income), age), "[Gender, income | AGE]"), + (((gender,), (age, income)), "[Gender | AGE, income]"), + (((gender,), (age, income), (ssn,)), + "[Gender | AGE, income] {SSN}"), + (((gender,), (age, income), (ssn, race)), + "[Gender | AGE, income] {SSN, race}"), + (((), (), (ssn, race)), "[] {SSN, race}"), + ) + + for args, printout in cases: + self.assertEqual(str(Domain(*args)), printout) + + def test_has_discrete(self): + self.assertFalse(Domain([]).has_discrete_attributes()) + self.assertFalse(Domain([], [age]).has_discrete_attributes()) + self.assertFalse(Domain([], race).has_discrete_attributes()) + + self.assertFalse(Domain([age], None).has_discrete_attributes()) + self.assertTrue(Domain([race], None).has_discrete_attributes()) + self.assertTrue(Domain([age, race], None).has_discrete_attributes()) + self.assertTrue(Domain([race, age], None).has_discrete_attributes()) + + self.assertFalse(Domain([], [age]).has_discrete_attributes(True)) + self.assertTrue(Domain([], [race]).has_discrete_attributes(True)) + self.assertFalse(Domain([age], None).has_discrete_attributes(True)) + self.assertTrue(Domain([race], None).has_discrete_attributes(True)) + self.assertTrue(Domain([age], race).has_discrete_attributes(True)) + self.assertTrue(Domain([race], age).has_discrete_attributes(True)) + self.assertTrue(Domain([], [race, age]).has_discrete_attributes(True)) + + d = Domain([], None, [gender]) + self.assertTrue(d.has_discrete_attributes(False, True)) + d = Domain([], None, [age]) + self.assertFalse(d.has_discrete_attributes(False, True)) + d = Domain([], [age], [gender]) + self.assertTrue(d.has_discrete_attributes(True, True)) + d = Domain([], [incomeA], [age]) + self.assertFalse(d.has_discrete_attributes(True, True)) + + def test_has_continuous(self): + self.assertFalse(Domain([]).has_continuous_attributes()) + self.assertFalse(Domain([], [age]).has_continuous_attributes()) + self.assertFalse(Domain([], [race]).has_continuous_attributes()) + + self.assertTrue(Domain([age], None).has_continuous_attributes()) + self.assertFalse(Domain([race], None).has_continuous_attributes()) + self.assertTrue(Domain([age, race], None).has_continuous_attributes()) + self.assertTrue(Domain([race, age], None).has_continuous_attributes()) + + self.assertTrue(Domain([], [age]).has_continuous_attributes(True)) + self.assertFalse(Domain([], [race]).has_continuous_attributes(True)) + self.assertTrue(Domain([age], None).has_continuous_attributes(True)) + self.assertFalse(Domain([race], None).has_continuous_attributes(True)) + self.assertTrue(Domain([age], race).has_continuous_attributes(True)) + self.assertTrue(Domain([race], age).has_continuous_attributes(True)) + self.assertTrue(Domain([], [race, age]).has_continuous_attributes(True)) + + d = Domain([], None, [age]) + self.assertTrue(d.has_continuous_attributes(False, True)) + d = Domain([], None, [gender]) + self.assertFalse(d.has_continuous_attributes(False, True)) + d = Domain([], [gender], [age]) + self.assertTrue(d.has_continuous_attributes(True, True)) + d = Domain([], [race], [gender]) + self.assertFalse(d.has_continuous_attributes(True, True)) + + def test_has_time(self): + self.assertFalse(Domain([]).has_time_attributes()) + self.assertFalse(Domain([], [age]).has_time_attributes()) + self.assertFalse(Domain([], [race]).has_time_attributes()) + self.assertFalse(Domain([], [arrival]).has_time_attributes()) + self.assertFalse(Domain([], [], [arrival]).has_time_attributes()) + + self.assertTrue(Domain([arrival], []).has_time_attributes()) + self.assertTrue(Domain([], [arrival]).has_time_attributes( + include_class=True)) + self.assertTrue(Domain([], [], [arrival]).has_time_attributes( + include_metas=True)) + + self.assertFalse(Domain([arrival], []).has_time_class) + self.assertTrue(Domain([], [arrival]).has_time_class) + self.assertFalse(Domain([], [], [arrival]).has_time_class) + + def test_get_conversion(self): + compute_value = lambda: 42 + new_income = income.copy(compute_value=compute_value) + + d = Domain((age, gender, income), metas=(ssn, race)) + e = Domain((gender, race), None, metas=(age, gender, ssn)) + f = Domain((gender,), (race, income), metas=(age, income, ssn)) + g = Domain((), metas=(age, gender, ssn)) + h = Domain((gender,), (race, new_income), metas=(age, new_income, ssn)) + + for conver, domain, attr, class_vars, metas in ( + (d, e, [1, -2], [], [0, 1, -1]), + (d, f, [1], [-2, 2], [0, 2, -1]), + (f, g, [], [], [-1, 0, -3]), + (g, h, [-2], [None, compute_value], [-1, compute_value, -3])): + to_domain = domain.get_conversion(conver) + self.assertIs(to_domain.source, conver) + self.assertEqual(to_domain.attributes, attr) + self.assertEqual(to_domain.class_vars, class_vars) + self.assertEqual(to_domain.metas, metas) + + def test_conversion(self): + domain = Domain([age, income], [race], + [gender, education, ssn]) + + x, y, metas = domain.convert([42, 13, "White"]) + assert_array_equal(x, np.array([42, 13])) + assert_array_equal(y, np.array([0])) + metas_exp = [gender.Unknown, education.Unknown, ssn.Unknown] + + def equal(a, b): + if isinstance(a, Real) and isinstance(b, Real) and \ + np.isnan(a) and np.isnan(b): + return True + else: + return a == b + + self.assertTrue(all(starmap(equal, zip(metas, metas_exp)))) + + x, y, metas = domain.convert([42, 13, "White", "M", "HS", "1234567"]) + assert_array_equal(x, np.array([42, 13])) + assert_array_equal(y, np.array([0])) + assert_array_equal(metas, np.array([0, 1, "1234567"], dtype=object)) + + def test_conversion_size(self): + domain = Domain([age, gender, income], [race]) + self.assertRaises(ValueError, domain.convert, [0] * 3) + self.assertRaises(ValueError, domain.convert, [0] * 5) + + domain = Domain([age, income], [race], + [gender, education, ssn]) + self.assertRaises(ValueError, domain.convert, [0] * 2) + self.assertRaises(ValueError, domain.convert, [0] * 4) + self.assertRaises(ValueError, domain.convert, [0] * 7) + domain.convert([0] * 3) + domain.convert([0] * 6) + + def test_preprocessor_chaining(self): + domain = Domain([DiscreteVariable("a", values="01"), + DiscreteVariable("b", values="01")], + DiscreteVariable("y", values="01")) + table = Table.from_list(domain, [[0, 1], [1, np.NaN]], [0, 1]) + pre1 = Continuize()(Impute()(table)) + pre2 = table.transform(pre1.domain) + np.testing.assert_almost_equal(pre1.X, pre2.X) + + def test_unpickling_recreates_known_domains(self): + domain = Domain([]) + unpickled_domain = pickle.loads(pickle.dumps(domain)) + self.assertTrue(hasattr(unpickled_domain, '_known_domains')) + + def test_different_domains_with_same_attributes_are_equal(self): + domain1 = Domain([]) + domain2 = Domain([]) + self.assertEqual(domain1, domain2) + + var1 = ContinuousVariable('var1') + domain1.attributes = (var1,) + self.assertNotEqual(domain1, domain2) + + domain2.attributes = (var1,) + self.assertEqual(domain1, domain2) + + domain1.class_vars = (var1,) + self.assertNotEqual(domain1, domain2) + + domain2.class_vars = (var1,) + self.assertEqual(domain1, domain2) + + domain1._metas = (var1,) + self.assertNotEqual(domain1, domain2) + + domain2._metas = (var1,) + self.assertEqual(domain1, domain2) + + def test_domain_conversion_is_fast_enough(self): + attrs = [ContinuousVariable("f%i" % i) for i in range(10000)] + class_vars = [ContinuousVariable("c%i" % i) for i in range(10)] + metas = [ContinuousVariable("m%i" % i) for i in range(10)] + source = Domain(attrs, class_vars, metas) + + start = time() + cases = (((attrs[:1000], class_vars, metas), + list(range(1000)), list(range(10000, 10010)), list(range(-1, -11, -1))), + ((metas, attrs[:1000], class_vars), + list(range(-1, -11, -1)), list(range(1000)), list(range(10000, 10010))), + ((class_vars, metas, attrs[:1000]), + list(range(10000, 10010)), list(range(-1, -11, -1)), list(range(1000)))) + + for domain_args, attributes, class_vars, metas in cases: + c1 = DomainConversion(source, Domain(*domain_args)) + self.assertEqual(c1.attributes, attributes) + self.assertEqual(c1.class_vars, class_vars) + self.assertEqual(c1.metas, metas) + + self.assertLessEqual(time() - start, 1) + + def test_copy(self): + age.number_of_decimals = 5 + attributes = (age, gender, income) + + domain = Domain(attributes, [race], [ssn]) + + new_domain = domain.copy() + new_domain[age].number_of_decimals = 10 + + self.assertEqual(domain[age].number_of_decimals, 5) + self.assertEqual(new_domain[age].number_of_decimals, 10) + + def test_domain_conversion_sparsity(self): + destination = Domain( + attributes=[ + ContinuousVariable(name='a'), + ContinuousVariable(name='b'), + ContinuousVariable(name='c'), + ], + class_vars=[DiscreteVariable('d', values=['e'])], + metas=[StringVariable('f')] + ) + + # all dense + source = Domain(attributes=[]) + conversion = DomainConversion(source, destination) + self.assertFalse(conversion.sparse_X) + self.assertFalse(conversion.sparse_Y) + self.assertFalse(conversion.sparse_metas) + + # set destination attributes as sparse + for a in destination.attributes: + a.sparse = True + source = Domain(attributes=[]) + conversion = DomainConversion(source, destination) + self.assertTrue(conversion.sparse_X) + self.assertFalse(conversion.sparse_Y) + self.assertFalse(conversion.sparse_metas) + + # set all destination variable as sparse + for a in chain(destination.variables, destination.metas): + a.sparse = True + source = Domain(attributes=[]) + conversion = DomainConversion(source, destination) + self.assertTrue(conversion.sparse_X) + self.assertTrue(conversion.sparse_Y) + self.assertFalse(conversion.sparse_metas) + + +class TestDomainFilter(unittest.TestCase): + def setUp(self): + self.iris = Table('iris') + + def test_filter_visible(self): + n_feats = len(self.iris.domain.attributes) + + self.iris.domain.attributes[0].attributes.update({'hidden': True}) + filtered = list(filter_visible(self.iris.domain.attributes)) + self.assertNotIn(self.iris.domain.attributes[0], filtered) + self.assertEqual(len(filtered), n_feats - 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_elliptic_envelope.py b/pyminer2/tests/test_elliptic_envelope.py new file mode 100644 index 0000000000000000000000000000000000000000..682e47f4abc2cd411bd58ad26eff85f8bcb81f9d --- /dev/null +++ b/pyminer2/tests/test_elliptic_envelope.py @@ -0,0 +1,62 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +from Orange.data import Table, Domain, ContinuousVariable +from Orange.classification import EllipticEnvelopeLearner + + +class TestEllipticEnvelopeLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + np.random.seed(42) + domain = Domain((ContinuousVariable("c1"), ContinuousVariable("c2"))) + cls.n_true_in, cls.n_true_out = 80, 20 + cls.X_in = 0.3 * np.random.randn(cls.n_true_in, 2) + cls.X_out = np.random.uniform(low=-4, high=4, + size=(cls.n_true_out, 2)) + cls.X_all = Table(domain, np.r_[cls.X_in, cls.X_out]) + cls.cont = cls.n_true_out / (cls.n_true_in + cls.n_true_out) + cls.learner = EllipticEnvelopeLearner(contamination=cls.cont) + cls.model = cls.learner(cls.X_all) + + def test_EllipticEnvelope(self): + y_pred = self.model(self.X_all) + n_pred_out_all = np.sum(y_pred == -1) + n_pred_in_true_in = np.sum(y_pred[:self.n_true_in] == 1) + n_pred_out_true_o = np.sum(y_pred[- self.n_true_out:] == -1) + + self.assertTrue(all(np.absolute(y_pred) == 1)) + self.assertGreaterEqual(len(self.X_all) * self.cont, n_pred_out_all) + self.assertGreater(1, np.absolute(n_pred_out_all - self.n_true_out)) + self.assertGreater(2, np.absolute(n_pred_in_true_in - self.n_true_in)) + self.assertGreater(2, np.absolute(n_pred_out_true_o - self.n_true_out)) + + def test_mahalanobis(self): + n = len(self.X_all) + y_pred = self.model(self.X_all) + y_mahal = self.model.mahalanobis(self.X_all) + y_mahal, y_pred = zip(*sorted(zip(y_mahal, y_pred), reverse=True)) + self.assertTrue(all(i == -1 for i in y_pred[:int(self.cont * n)])) + self.assertTrue(all(i == 1 for i in y_pred[int(self.cont * n):])) + + def test_EllipticEnvelope_ignores_y(self): + domain = Domain((ContinuousVariable("x1"), ContinuousVariable("x2")), + class_vars=(ContinuousVariable("y1"), ContinuousVariable("y2"))) + X = np.random.random((40, 2)) + Y = np.random.random((40, 2)) + table = Table(domain, X, Y) + classless_table = table.transform(Domain(table.domain.attributes)) + learner = EllipticEnvelopeLearner() + classless_model = learner(classless_table) + model = learner(table) + pred1 = classless_model(classless_table) + pred2 = classless_model(table) + pred3 = model(classless_table) + pred4 = model(table) + + np.testing.assert_array_equal(pred1, pred2) + np.testing.assert_array_equal(pred2, pred3) + np.testing.assert_array_equal(pred3, pred4) diff --git a/pyminer2/tests/test_evaluation_clustering.py b/pyminer2/tests/test_evaluation_clustering.py new file mode 100644 index 0000000000000000000000000000000000000000..a83e82ff364d63091e7832aac2fed0290b1dfaac --- /dev/null +++ b/pyminer2/tests/test_evaluation_clustering.py @@ -0,0 +1,48 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np + +import Orange +from Orange.evaluation.clustering import Silhouette, \ + AdjustedMutualInfoScore, ClusteringEvaluation, ClusteringResults +from Orange.clustering.kmeans import KMeans, KMeansModel + + +class TestClusteringResults(unittest.TestCase): + @staticmethod + def test_init(): + data = Orange.data.Table.from_numpy( + None, np.arange(100).reshape((100, 1))) + res = ClusteringResults(data=data, nmethods=2, nrows=100) + res.actual[:50] = 0 + res.actual[50:] = 1 + res.predicted = np.vstack((res.actual, res.actual)) + expected = [1.0, 1.0] + np.testing.assert_almost_equal(AdjustedMutualInfoScore(res), expected) + + +class TestClusteringEvaluation(unittest.TestCase): + def test_init(self): + res = ClusteringEvaluation(k=42) + self.assertEqual(res.k, 42) + + def test_kmeans(self): + table = Orange.data.Table('iris') + cr = ClusteringEvaluation(k=3)(table, learners=[KMeans(n_clusters=2), + KMeans(n_clusters=3), + KMeans(n_clusters=5)]) + expected = [0.68081362, 0.55259194, 0.48851755] + np.testing.assert_almost_equal(Silhouette(cr), expected, decimal=2) + expected = [0.65383807, 0.75511917, 0.68721092] + np.testing.assert_almost_equal(AdjustedMutualInfoScore(cr), + expected, decimal=2) + self.assertIsNone(cr.models) + + cr = ClusteringEvaluation(k=3, store_models=True)( + table, learners=[KMeans(n_clusters=2)]) + self.assertEqual(cr.models.shape, (3, 1)) + self.assertTrue(all(isinstance(m, KMeansModel) + for m in cr.models.flatten())) diff --git a/pyminer2/tests/test_evaluation_scoring.py b/pyminer2/tests/test_evaluation_scoring.py new file mode 100644 index 0000000000000000000000000000000000000000..25477298dbbf26edc297ab4f7c120d0682ac904c --- /dev/null +++ b/pyminer2/tests/test_evaluation_scoring.py @@ -0,0 +1,439 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np + +from Orange.data import DiscreteVariable, ContinuousVariable, Domain +from Orange.data import Table +from Orange.classification import LogisticRegressionLearner, SklTreeLearner, NaiveBayesLearner,\ + MajorityLearner +from Orange.evaluation import AUC, CA, Results, Recall, \ + Precision, TestOnTrainingData, scoring, LogLoss, F1, CrossValidation +from Orange.evaluation.scoring import Specificity +from Orange.preprocess import discretize, Discretize +from Orange.tests import test_filename + + +class TestScoreMetaType(unittest.TestCase): + class BaseScore(metaclass=scoring.ScoreMetaType): + pass + + class Score1(BaseScore, abstract=True): + class_types = (DiscreteVariable,) + + class Score2(Score1): + pass + + class Score3(Score2): + name = "foo" + + class Score4(Score2): + pass + + class Score5(BaseScore): + class_types = (DiscreteVariable, ContinuousVariable) + + def test_registry(self): + """All non-abstract classes appear in the registry""" + self.assertEqual( + self.BaseScore.registry, + {"Score2": self.Score2, "Score3": self.Score3, + "Score4": self.Score4, "Score5": self.Score5}) + + def test_names(self): + """Attribute `name` defaults to class and is not inherited""" + self.assertEqual(self.Score2.name, "Score2") + self.assertEqual(self.Score3.name, "foo") + self.assertEqual(self.Score4.name, "Score4") + self.assertEqual(self.Score5.name, "Score5") + + +class TestPrecision(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.score = Precision() + + def test_precision_iris(self): + learner = LogisticRegressionLearner(preprocessors=[]) + res = TestOnTrainingData()(self.iris, [learner]) + self.assertAlmostEqual(self.score(res, average='weighted')[0], + 0.96189, 5) + self.assertAlmostEqual(self.score(res, target=1)[0], 0.97826, 5) + self.assertAlmostEqual(self.score(res, target=1, average=None)[0], + 0.97826, 5) + self.assertAlmostEqual(self.score(res, target=1, average='weighted')[0], + 0.97826, 5) + self.assertAlmostEqual(self.score(res, target=0, average=None)[0], 1, 5) + self.assertAlmostEqual(self.score(res, target=2, average=None)[0], + 0.90741, 5) + + def test_precision_multiclass(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01234")), + actual=[0, 4, 4, 1, 2, 0, 1, 2, 3, 2]) + results.predicted = np.array([[0, 4, 4, 1, 2, 0, 1, 2, 3, 2], + [0, 1, 4, 1, 1, 0, 0, 2, 3, 1]]) + res = self.score(results, average='weighted') + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 0.78333, 5) + + for target, prob in ((0, 2 / 3), + (1, 1 / 4), + (2, 1 / 1), + (3, 1 / 1), + (4, 1 / 1)): + res = self.score(results, target=target, average=None) + self.assertEqual(res[0], 1.) + self.assertEqual(res[1], prob) + + def test_precision_binary(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01")), + actual=[0, 1, 1, 1, 0, 0, 1, 0, 0, 1]) + results.predicted = np.array([[0, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 1, 1, 1, 0, 0, 1, 1, 1, 0]]) + res = self.score(results) + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 4 / 6) + res_target = self.score(results, target=1) + self.assertEqual(res[0], res_target[0]) + self.assertEqual(res[1], res_target[1]) + res_target = self.score(results, target=0) + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], 3 / 4) + res_target = self.score(results, average='macro') + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], (4 / 6 + 3 / 4) / 2) + + +class TestRecall(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.score = Recall() + + def test_recall_iris(self): + learner = LogisticRegressionLearner(preprocessors=[]) + res = TestOnTrainingData()(self.iris, [learner]) + self.assertAlmostEqual(self.score(res, average='weighted')[0], 0.96, 5) + self.assertAlmostEqual(self.score(res, target=1)[0], 0.9, 5) + self.assertAlmostEqual(self.score(res, target=1, average=None)[0], + 0.9, 5) + self.assertAlmostEqual(self.score(res, target=1, average='weighted')[0], + 0.9, 5) + self.assertAlmostEqual(self.score(res, target=0, average=None)[0], 1, 5) + self.assertAlmostEqual(self.score(res, target=2, average=None)[0], + 0.98, 5) + + def test_recall_multiclass(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01234")), + actual=[0, 4, 4, 1, 2, 0, 1, 2, 3, 2]) + results.predicted = np.array([[0, 4, 4, 1, 2, 0, 1, 2, 3, 2], + [0, 1, 4, 1, 1, 0, 0, 2, 3, 1]]) + res = self.score(results, average='weighted') + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 0.6) + + for target, prob in ((0, 2 / 2), + (1, 1 / 2), + (2, 1 / 3), + (3, 1 / 1), + (4, 1 / 2)): + res = self.score(results, target=target) + self.assertEqual(res[0], 1.) + self.assertEqual(res[1], prob) + + def test_recall_binary(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01")), + actual=[0, 1, 1, 1, 0, 0, 1, 0, 0, 1]) + results.predicted = np.array([[0, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 1, 1, 1, 0, 0, 1, 1, 1, 0]]) + res = self.score(results) + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 4 / 5) + res_target = self.score(results, target=1) + self.assertEqual(res[0], res_target[0]) + self.assertEqual(res[1], res_target[1]) + res_target = self.score(results, target=0) + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], 3 / 5) + res_target = self.score(results, average='macro') + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], (4 / 5 + 3 / 5) / 2) + + +class TestF1(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.score = F1() + + def test_recall_iris(self): + learner = LogisticRegressionLearner(preprocessors=[]) + res = TestOnTrainingData()(self.iris, [learner]) + self.assertAlmostEqual(self.score(res, average='weighted')[0], + 0.959935, 5) + self.assertAlmostEqual(self.score(res, target=1)[0], 0.9375, 5) + self.assertAlmostEqual(self.score(res, target=1, average=None)[0], + 0.9375, 5) + self.assertAlmostEqual(self.score(res, target=1, average='weighted')[0], + 0.9375, 5) + self.assertAlmostEqual(self.score(res, target=0, average=None)[0], 1, 5) + self.assertAlmostEqual(self.score(res, target=2, average=None)[0], + 0.942307, 5) + + def test_F1_multiclass(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01234")), + actual=[0, 4, 4, 1, 2, 0, 1, 2, 3, 2]) + results.predicted = np.array([[0, 4, 4, 1, 2, 0, 1, 2, 3, 2], + [0, 1, 4, 1, 1, 0, 0, 2, 3, 1]]) + res = self.score(results, average='weighted') + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 0.61) + + for target, prob in ((0, 4 / 5), + (1, 1 / 3), + (2, 1 / 2), + (3, 1.), + (4, 2 / 3)): + res = self.score(results, target=target) + self.assertEqual(res[0], 1.) + self.assertEqual(res[1], prob) + + def test_F1_binary(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01")), + actual=[0, 1, 1, 1, 0, 0, 1, 0, 0, 1]) + results.predicted = np.array([[0, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 1, 1, 1, 0, 0, 1, 1, 1, 1]]) + res = self.score(results) + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 5 / 6) + res_target = self.score(results, target=1) + self.assertEqual(res[0], res_target[0]) + self.assertEqual(res[1], res_target[1]) + res_target = self.score(results, target=0) + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], 3 / 4) + + +class TestCA(unittest.TestCase): + def test_init(self): + res = Results(nmethods=2, nrows=100) + res.actual[:50] = 0 + res.actual[50:] = 1 + res.predicted = np.vstack((res.actual, res.actual)) + np.testing.assert_almost_equal(CA(res), [1, 1]) + + res.predicted[0][0] = 1 + np.testing.assert_almost_equal(CA(res), [0.99, 1]) + + res.predicted[1] = 1 - res.predicted[1] + np.testing.assert_almost_equal(CA(res), [0.99, 0]) + + def test_call(self): + res = Results(nmethods=2, nrows=100) + res.actual[:50] = 0 + res.actual[50:] = 1 + res.predicted = np.vstack((res.actual, res.actual)) + ca = CA() + np.testing.assert_almost_equal(ca(res), [1, 1]) + + res.predicted[0][0] = 1 + np.testing.assert_almost_equal(ca(res), [0.99, 1]) + + res.predicted[1] = 1 - res.predicted[1] + np.testing.assert_almost_equal(ca(res), [0.99, 0]) + + def test_bayes(self): + x = np.random.randint(2, size=(100, 5)) + col = np.random.randint(5) + y = x[:, col].copy().reshape(100, 1) + t = Table.from_numpy(None, x, y) + t = Discretize( + method=discretize.EqualWidth(n=3))(t) + nb = NaiveBayesLearner() + res = TestOnTrainingData()(t, [nb]) + np.testing.assert_almost_equal(CA(res), [1]) + + t.Y[-20:] = 1 - t.Y[-20:] + res = TestOnTrainingData()(t, [nb]) + self.assertGreaterEqual(CA(res)[0], 0.75) + self.assertLess(CA(res)[0], 1) + + +class TestAUC(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + + def test_tree(self): + tree = SklTreeLearner() + res = CrossValidation(k=2)(self.iris, [tree]) + self.assertGreater(AUC(res)[0], 0.8) + self.assertLess(AUC(res)[0], 1.) + + def test_constant_prob(self): + maj = MajorityLearner() + res = TestOnTrainingData()(self.iris, [maj]) + self.assertEqual(AUC(res)[0], 0.5) + + def test_multiclass_auc_multi_learners(self): + learners = [LogisticRegressionLearner(), + MajorityLearner()] + res = CrossValidation(k=10)(self.iris, learners) + self.assertGreater(AUC(res)[0], 0.6) + self.assertLess(AUC(res)[1], 0.6) + self.assertGreater(AUC(res)[1], 0.4) + + def test_auc_on_multiclass_data_returns_1d_array(self): + titanic = Table('titanic')[:100] + lenses = Table(test_filename('datasets/lenses.tab'))[:100] + majority = MajorityLearner() + + results = TestOnTrainingData()(lenses, [majority]) + auc = AUC(results) + self.assertEqual(auc.ndim, 1) + + results = TestOnTrainingData()(titanic, [majority]) + auc = AUC(results) + self.assertEqual(auc.ndim, 1) + + def test_auc_scores(self): + actual = np.array([0., 0., 0., 1., 1., 1.]) + for predicted, auc in (([1., 1., 1., 0., 0., 0.], 0.), # All wrong + ([0., 0., 0., 0., 0., 0.], 0.5), # All with same probability + ([0., 0., 0., 1., 1., 1.], 1.), # All correct + ([0., 0., 0., 1., 1., 0.], 5 / 6), # One wrong + ([1., 1., 0., 1., 1., 1.], 4 / 6), # Two wrong + ([1., 1., 0., 1., 1., 0.], 3 / 6)): # Three wrong + self.assertAlmostEqual(self.compute_auc(actual, predicted), auc) + + def compute_auc(self, actual, predicted): + predicted = np.array(predicted).reshape(1, -1) + probabilities = np.zeros((1, predicted.shape[1], 2)) + probabilities[0, :, 1] = predicted[0] + probabilities[0, :, 0] = 1 - predicted[0] + results = Results( + nmethods=1, domain=Domain([], [DiscreteVariable("x", values='01')]), + actual=actual, predicted=predicted) + results.probabilities = probabilities + return AUC(results)[0] + + +class TestComputeCD(unittest.TestCase): + def test_compute_CD(self): + avranks = [1.9, 3.2, 2.8, 3.3] + cd = scoring.compute_CD(avranks, 30) + np.testing.assert_almost_equal(cd, 0.856344) + + cd = scoring.compute_CD(avranks, 30, test="bonferroni-dunn") + np.testing.assert_almost_equal(cd, 0.798) + + # Do what you will, just don't crash + scoring.graph_ranks(avranks, "abcd", cd) + scoring.graph_ranks(avranks, "abcd", cd, cdmethod=0) + + +class TestLogLoss(unittest.TestCase): + def test_log_loss(self): + data = Table('iris') + majority = MajorityLearner() + results = TestOnTrainingData()(data, [majority]) + ll = LogLoss(results) + self.assertAlmostEqual(ll[0], - np.log(1 / 3)) + + def _log_loss(self, act, prob): + ll = np.dot(np.log(prob[:, 0]), act[:, 0]) + \ + np.dot(np.log(prob[:, 1]), act[:, 1]) + return - ll / len(act) + + def test_log_loss_calc(self): + data = Table('titanic') + learner = LogisticRegressionLearner() + results = TestOnTrainingData()(data, [learner]) + + actual = np.copy(results.actual) + actual = actual.reshape(actual.shape[0], 1) + actual = np.hstack((1 - actual, actual)) + probab = results.probabilities[0] + + ll_calc = self._log_loss(actual, probab) + ll_orange = LogLoss(results) + self.assertAlmostEqual(ll_calc, ll_orange[0]) + + +class TestSpecificity(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.score = Specificity() + + def test_specificity_iris(self): + learner = LogisticRegressionLearner(preprocessors=[]) + res = TestOnTrainingData()(self.iris, [learner]) + self.assertAlmostEqual(self.score(res, average='weighted')[0], + (1 + 0.99 + 0.95) / 3, 5) + self.assertAlmostEqual(self.score(res, target=1)[0], 99 / (99 + 1), 5) + self.assertAlmostEqual(self.score(res, target=1, average=None)[0], + 99 / (99 + 1), 5) + self.assertAlmostEqual(self.score(res, target=1, average='weighted')[0], + 99 / (99 + 1), 5) + self.assertAlmostEqual(self.score(res, target=0, average=None)[0], 1, 5) + self.assertAlmostEqual(self.score(res, target=2, average=None)[0], + 95 / (95 + 5), 5) + + def test_precision_multiclass(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01234")), + actual=[0, 4, 4, 1, 2, 0, 1, 2, 3, 2]) + results.predicted = np.array([[0, 4, 4, 1, 2, 0, 1, 2, 3, 2], + [0, 1, 4, 1, 1, 0, 0, 2, 3, 1]]) + res = self.score(results, average='weighted') + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 0.9, 5) + + for target, prob in ((0, 7 / 8), + (1, 5 / 8), + (2, 1), + (3, 1), + (4, 1)): + res = self.score(results, target=target, average=None) + self.assertEqual(res[0], 1.) + self.assertEqual(res[1], prob) + + def test_precision_binary(self): + results = Results( + domain=Domain([], DiscreteVariable(name="y", values="01")), + actual=[0, 1, 1, 1, 0, 0, 1, 0, 0, 1]) + results.predicted = np.array([[0, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 1, 1, 1, 0, 0, 1, 1, 1, 0]]) + res = self.score(results) + self.assertEqual(res[0], 1.) + self.assertAlmostEqual(res[1], 3 / 5) + res_target = self.score(results, target=1) + self.assertEqual(res[0], res_target[0]) + self.assertEqual(res[1], res_target[1]) + res_target = self.score(results, target=0) + self.assertEqual(res_target[0], 1.) + self.assertAlmostEqual(res_target[1], 4 / 5) + + def test_errors(self): + learner = LogisticRegressionLearner(preprocessors=[]) + res = TestOnTrainingData()(self.iris, [learner]) + + # binary average does not work for number of classes different than 2 + self.assertRaises(ValueError, self.score, res, average="binary") + + # implemented only weighted and binary averaging + self.assertRaises(ValueError, self.score, res, average="abc") + + +if __name__ == '__main__': + unittest.main() + del TestScoreMetaType diff --git a/pyminer2/tests/test_evaluation_testing.py b/pyminer2/tests/test_evaluation_testing.py new file mode 100644 index 0000000000000000000000000000000000000000..561be10c6aa901cdbab87cbde5ee561cef0f4fa8 --- /dev/null +++ b/pyminer2/tests/test_evaluation_testing.py @@ -0,0 +1,886 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import Mock, patch + +import numpy as np + +from Orange.classification import NaiveBayesLearner, MajorityLearner +from Orange.evaluation.testing import Validation +from Orange.regression import LinearRegressionLearner, MeanLearner +from Orange.data import Table, Domain, DiscreteVariable +from Orange.evaluation import (Results, CrossValidation, LeaveOneOut, TestOnTrainingData, + TestOnTestData, ShuffleSplit, sample, RMSE, + CrossValidationFeature) +from Orange.preprocess import discretize, preprocess + + +def random_data(nrows, ncols): + np.random.seed(42) + x = np.random.randint(0, 2, (nrows, ncols)) + col = np.random.randint(ncols) + y = x[:nrows, col].reshape(nrows, 1) + table = Table.from_numpy(None, x, y) + table = preprocess.Discretize(discretize.EqualWidth(n=3))(table) + return table + + +class TestingTestCase(unittest.TestCase): + def test_no_data(self): + self.assertRaises(ValueError, CrossValidation, + learners=[NaiveBayesLearner()]) + + +class _ParameterTuningLearner(MajorityLearner): + def __call__(self, data): + learner = MajorityLearner() + CrossValidation(data, [learner], k=2) + return learner(data) + + +# noinspection PyUnresolvedReferences +class TestSampling(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.nrows = 200 + cls.ncols = 5 + cls.random_table = random_data(cls.nrows, cls.ncols) + + def run_test_failed(self, method, succ_calls): + # Can't use mocking helpers here (wrong result type for Majority, + # exception caught for fails) + def major(*args): + nonlocal major_call + major_call += 1 + return MajorityLearner()(*args) + + def fails(_): + nonlocal fail_calls + fail_calls += 1 + raise SystemError("failing learner") + + major_call = 0 + fail_calls = 0 + res = method()(random_data(50, 4), [major, fails, major]) + self.assertFalse(res.failed[0]) + self.assertIsInstance(res.failed[1], Exception) + self.assertFalse(res.failed[2]) + self.assertEqual(major_call, succ_calls) + self.assertEqual(fail_calls, succ_calls / 2) + + def run_test_callback(self, method, expected_progresses): + def record_progress(p): + progress.append(p) + progress = [] + method()( + self.random_table, [MajorityLearner(), MajorityLearner()], + callback=record_progress) + np.testing.assert_almost_equal(np.array(progress), expected_progresses) + + def run_test_preprocessor(self, method, expected_sizes): + def preprocessor(data): + data_sizes.append(len(data)) + return data + data_sizes = [] + method()(Table('iris'), [MajorityLearner(), MajorityLearner()], + preprocessor=preprocessor) + self.assertEqual(data_sizes, expected_sizes) + + def check_folds(self, result, folds_count, rows): + self.assertEqual(len(result.folds), folds_count) + fold_size = rows / folds_count + for i, fold in enumerate(result.folds): + self.assertAlmostEqual(fold.start, i * fold_size, delta=3) + self.assertAlmostEqual(fold.stop, (i + 1) * fold_size, delta=3) + + def check_models(self, result, learners, folds): + self.assertEqual(result.models.shape, (folds, len(learners))) + for models in result.models: + for model, learner in zip(models, learners): + self.assertIsInstance(model, learner.__returns__) + + @staticmethod + def _callback_values(iterations): + return np.hstack((np.linspace(0., .99, iterations + 1)[1:], [1])) + + +class TestValidation(unittest.TestCase): + def setUp(self): + self.data = Table('iris') + + def test_invalid_argument_combination(self): + self.assertRaises(ValueError, Validation, self.data) + self.assertRaises(ValueError, Validation, None, [MajorityLearner()]) + self.assertRaises(ValueError, Validation, preprocessor=lambda x: x) + self.assertRaises(ValueError, Validation, callback=lambda x: x) + + @patch("Orange.evaluation.testing.Validation.__call__") + def test_warn_deprecations(self, _): + self.assertWarns( + DeprecationWarning, + Validation, self.data, [MajorityLearner()]) + + self.assertWarns(DeprecationWarning, Validation().fit) + + @patch("Orange.evaluation.testing.Validation.__call__") + def test_obsolete_call_constructor(self, validation_call): + + class MockValidation(Validation): + args = kwargs = None + + def __init__(self, *args, **kwargs): + super().__init__() + MockValidation.args = args + MockValidation.kwargs = kwargs + + def get_indices(self, data): + pass + + data = self.data + learners = [MajorityLearner(), MajorityLearner()] + kwargs = dict(foo=42, store_data=43, store_models=44, callback=45, n_jobs=46) + self.assertWarns( + DeprecationWarning, + MockValidation, data, learners=learners, + **kwargs) + self.assertEqual(MockValidation.args, ()) + kwargs.pop("n_jobs") # do not pass n_jobs and callback from __new__ to __init__ + kwargs.pop("callback") + self.assertEqual(MockValidation.kwargs, kwargs) + + cargs, ckwargs = validation_call.call_args + self.assertEqual(len(cargs), 1) + self.assertIs(cargs[0], data) + self.assertIs(ckwargs["learners"], learners) + self.assertEqual(ckwargs["callback"], 45) + + +class TestCrossValidation(TestSampling): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.housing = Table('housing') + cls.nrows = 50 + cls.ncols = 5 + cls.random_table = random_data(cls.nrows, cls.ncols) + + def test_init(self): + res = CrossValidation(k=42, stratified=False, random_state=43) + self.assertEqual(res.k, 42) + self.assertFalse(res.stratified) + self.assertEqual(res.random_state, 43) + + def test_results(self): + nrows, _ = self.random_table.X.shape + res = CrossValidation(k=10, stratified=False)( + self.random_table, [NaiveBayesLearner()]) + y = self.random_table.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + self.check_folds(res, 10, nrows) + + def test_continuous(self): + res = CrossValidation(k=3)( + self.housing, [LinearRegressionLearner()]) + self.assertLess(RMSE(res), 5) + + def test_folds(self): + res = CrossValidation(k=5)(self.random_table, [NaiveBayesLearner()]) + self.check_folds(res, 5, self.nrows) + + def test_call_5(self): + nrows, _ = self.random_table.X.shape + res = CrossValidation(k=5, stratified=False)( + self.random_table, [NaiveBayesLearner()]) + y = self.random_table.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + self.check_folds(res, 5, nrows) + + def test_store_data(self): + learners = [NaiveBayesLearner()] + res = CrossValidation(store_data=False)(self.random_table, learners) + self.assertIsNone(res.data) + + res = CrossValidation(store_data=True)(self.random_table, learners) + self.assertIs(res.data, self.random_table) + + def test_store_models(self): + learners = [NaiveBayesLearner(), MajorityLearner()] + + res = CrossValidation(store_models=False, k=5)( + self.random_table, learners) + self.assertIsNone(res.models) + + res = CrossValidation(k=5, store_models=True)(self.random_table, learners) + self.assertEqual(len(res.models), 5) + self.check_models(res, learners, 5) + + def test_split_by_model(self): + learners = [NaiveBayesLearner(), MajorityLearner()] + res = CrossValidation(k=5, store_models=True)(self.random_table, learners) + + for i, result in enumerate(res.split_by_model()): + self.assertIsInstance(result, Results) + self.assertTrue((result.predicted == res.predicted[i]).all()) + self.assertTrue((result.probabilities == res.probabilities[i]).all()) + self.assertEqual(len(result.models), 5) + for model in result.models[0]: + self.assertIsInstance(model, learners[i].__returns__) + self.assertSequenceEqual(result.learners, [res.learners[i]]) + + def test_10_fold_probs(self): + learners = [MajorityLearner(), MajorityLearner()] + + results = CrossValidation(k=10)(self.iris[30:130], learners) + + self.assertEqual(results.predicted.shape, (2, len(self.iris[30:130]))) + np.testing.assert_equal(results.predicted, np.ones((2, 100))) + probs = results.probabilities + self.assertTrue((probs[:, :, 0] < probs[:, :, 2]).all()) + self.assertTrue((probs[:, :, 2] < probs[:, :, 1]).all()) + + @staticmethod + def test_miss_majority(): + x = np.zeros((50, 3)) + y = x[:, -1] + x[-4:] = np.ones((4, 3)) + data = Table.from_numpy(None, x, y) + cv = CrossValidation(k=3) + res = cv(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[-4:] = np.zeros((4, 3)) + res = cv(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + def test_too_many_folds(self): + w = [] + CrossValidation(k=len(self.iris) // 2, warnings=w)( + self.iris, [MajorityLearner()]) + self.assertGreater(len(w), 0) + + def test_failed(self): + self.run_test_failed(CrossValidation, 20) + + def test_callback(self): + self.run_test_callback(CrossValidation, self._callback_values(20)) + + def test_preprocessor(self): + self.run_test_preprocessor(CrossValidation, [135] * 10) + + def test_augmented_data_classification(self): + data = Table("iris") + n_classes = len(data.domain.class_var.values) + res = CrossValidation(store_data=True)(data, [NaiveBayesLearner()]) + table = res.get_augmented_data(['Naive Bayes']) + + self.assertEqual(len(table), len(data)) + self.assertEqual(len(table.domain.attributes), len(data.domain.attributes)) + self.assertEqual(len(table.domain.class_vars), len(data.domain.class_vars)) + # +1 for class, +n_classes for probabilities, +1 for fold + self.assertEqual( + len(table.domain.metas), len(data.domain.metas) + 1 + n_classes + 1) + self.assertEqual( + table.domain.metas[len(data.domain.metas)].values, data.domain.class_var.values) + + res = CrossValidation(store_data=True)(data, [NaiveBayesLearner(), MajorityLearner()]) + table = res.get_augmented_data(['Naive Bayes', 'Majority']) + + self.assertEqual(len(table), len(data)) + self.assertEqual(len(table.domain.attributes), len(data.domain.attributes)) + self.assertEqual(len(table.domain.class_vars), len(data.domain.class_vars)) + self.assertEqual( + len(table.domain.metas), len(data.domain.metas) + 2*(n_classes+1) + 1) + self.assertEqual( + table.domain.metas[len(data.domain.metas)].values, data.domain.class_var.values) + self.assertEqual( + table.domain.metas[len(data.domain.metas)+1].values, data.domain.class_var.values) + + def test_augmented_data_regression(self): + data = Table("housing") + res = CrossValidation(store_data=True)(data, [LinearRegressionLearner()]) + table = res.get_augmented_data(['Linear Regression']) + + self.assertEqual(len(table), len(data)) + self.assertEqual(len(table.domain.attributes), len(data.domain.attributes)) + self.assertEqual(len(table.domain.class_vars), len(data.domain.class_vars)) + # +1 for class, +1 for fold + self.assertEqual(len(table.domain.metas), len(data.domain.metas) + 1 + 1) + + res = CrossValidation(store_data=True)(data, [LinearRegressionLearner(), MeanLearner()]) + table = res.get_augmented_data(['Linear Regression', 'Mean Learner']) + + self.assertEqual(len(table), len(data)) + self.assertEqual(len(table.domain.attributes), len(data.domain.attributes)) + self.assertEqual(len(table.domain.class_vars), len(data.domain.class_vars)) + # +2 for class, +1 for fold + self.assertEqual(len(table.domain.metas), len(data.domain.metas) + 2 + 1) + + +class TestCrossValidationFeature(TestSampling): + + @staticmethod + def add_meta_fold(data, f): + fat = DiscreteVariable(name="fold", values=[str(a) for a in range(f)]) + domain = Domain(data.domain.attributes, data.domain.class_var, metas=[fat]) + ndata = data.transform(domain) + vals = np.tile(range(f), len(data)//f + 1)[:len(data)] + vals = vals.reshape((-1, 1)) + ndata[:, fat] = vals + return ndata + + def test_init(self): + var = DiscreteVariable(name="fold", values="abc") + res = CrossValidationFeature(feature=var) + self.assertIs(res.feature, var) + + def test_call(self): + t = self.random_table + t = self.add_meta_fold(t, 3) + res = CrossValidationFeature(feature=t.domain.metas[0])(t, [NaiveBayesLearner()]) + y = t.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(len(t))) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(len(t))) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(len(t))) + + def test_unknown(self): + t = self.random_table + t = self.add_meta_fold(t, 3) + fat = t.domain.metas[0] + t[0][fat] = float("nan") + res = CrossValidationFeature(feature=fat)(t, [NaiveBayesLearner()]) + self.assertNotIn(0, res.row_indices) + + def test_bad_feature(self): + feat = DiscreteVariable(name="fold", values="abc") + domain = Domain([DiscreteVariable("x", values="ab")], + DiscreteVariable("y", values="cd"), + metas=[feat]) + t = Table.from_numpy( + domain, + np.zeros((10, 1)), np.ones((10, 1)), np.full((10, 1), np.nan)) + self.assertRaises( + ValueError, + CrossValidationFeature(feature=feat), t, [NaiveBayesLearner()]) + + +class TestLeaveOneOut(TestSampling): + def test_results(self): + nrows = self.nrows + t = self.random_table + res = LeaveOneOut()(t, [NaiveBayesLearner()]) + y = t.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.row_indices, np.arange(nrows)) + + def test_call(self): + nrows = self.nrows + t = self.random_table + res = LeaveOneOut()(t, [NaiveBayesLearner()]) + y = t.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + + def test_store_data(self): + t = self.random_table + learners = [NaiveBayesLearner()] + + res = LeaveOneOut(store_data=False)(t, learners) + self.assertIsNone(res.data) + + res = LeaveOneOut(store_data=True)(t, learners) + self.assertIs(res.data, t) + + def test_store_models(self): + t = self.random_table + learners = [NaiveBayesLearner(), MajorityLearner()] + + res = LeaveOneOut()(t, learners) + self.assertIsNone(res.models) + + res = LeaveOneOut(store_models=True)(t, learners) + self.check_models(res, learners, self.nrows) + + def test_probs(self): + data = Table('iris')[30:130] + learners = [MajorityLearner(), MajorityLearner()] + + results = LeaveOneOut()(data, learners) + + self.assertEqual(results.predicted.shape, (2, len(data))) + np.testing.assert_equal(results.predicted, np.ones((2, 100))) + probs = results.probabilities + self.assertTrue((probs[:, :, 0] < probs[:, :, 2]).all()) + self.assertTrue((probs[:, :, 2] < probs[:, :, 1]).all()) + + @staticmethod + def test_miss_majority(): + x = np.zeros((50, 3)) + y = x[:, -1] + x[49] = 1 + data = Table.from_numpy(None, x, y) + res = LeaveOneOut()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[49] = 0 + res = LeaveOneOut()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[25:] = 1 + data = Table.from_numpy(None, x, y) + res = LeaveOneOut()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0], + 1 - data.Y[res.row_indices].flatten()) + + def test_failed(self): + self.run_test_failed(LeaveOneOut, 100) + + def test_callback(self): + self.run_test_callback(LeaveOneOut, self._callback_values(2 * self.nrows)) + + def test_preprocessor(self): + self.run_test_preprocessor(LeaveOneOut, [149] * 150) + + +class TestTestOnTrainingData(TestSampling): + @staticmethod + def _callback_values(iterations): + return np.hstack(((np.arange(iterations) + 1) / iterations, [1])) + + def test_results(self): + nrows, _ = self.random_table.X.shape + t = self.random_table + res = TestOnTrainingData()(t, [NaiveBayesLearner()]) + y = t.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.row_indices, np.arange(nrows)) + + def test_store_data(self): + t = self.random_table + learners = [NaiveBayesLearner()] + res = TestOnTrainingData()(t, learners) + self.assertIsNone(res.data) + res = TestOnTrainingData(store_data=True)(t, learners) + self.assertIs(res.data, t) + + def test_store_models(self): + t = self.random_table + learners = [NaiveBayesLearner(), MajorityLearner()] + + res = TestOnTrainingData()(t, learners) + self.assertIsNone(res.models) + + res = TestOnTrainingData(store_models=True)(t, learners) + self.check_models(res, learners, 1) + + def test_probs(self): + data = self.iris[30:130] + learners = [MajorityLearner(), MajorityLearner()] + + results = TestOnTrainingData()(data, learners) + + self.assertEqual(results.predicted.shape, (2, len(data))) + np.testing.assert_equal(results.predicted, np.ones((2, 100))) + probs = results.probabilities + self.assertTrue((probs[:, :, 0] < probs[:, :, 2]).all()) + self.assertTrue((probs[:, :, 2] < probs[:, :, 1]).all()) + + @staticmethod + def test_miss_majority(): + x = np.zeros((50, 3)) + y = x[:, -1] + x[49] = 1 + data = Table.from_numpy(None, x, y) + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[49] = 0 + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[25:] = 1 + data = Table.from_numpy(None, x, y) + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0], res.predicted[0][0]) + + def test_failed(self): + self.run_test_failed(TestOnTrainingData, 2) + + def test_callback(self): + self.run_test_callback(TestOnTrainingData, self._callback_values(2)) + + def test_preprocessor(self): + self.run_test_preprocessor(TestOnTrainingData, [150]) + + +class TestTestOnTestData(TestSampling): + @staticmethod + def _callback_values(iterations): + return np.hstack(((np.arange(iterations) + 1) / iterations, [1])) + + def test_results(self): + nrows, _ = self.random_table.X.shape + t = self.random_table + res = TestOnTestData()(t, t, [NaiveBayesLearner()]) + y = t.Y + np.testing.assert_equal(res.actual, y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.predicted[0], + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(np.argmax(res.probabilities[0], axis=1), + y[res.row_indices].reshape(nrows)) + np.testing.assert_equal(res.row_indices, np.arange(nrows)) + + def test_probs(self): + data = self.iris[30:130] + learners = [MajorityLearner(), MajorityLearner()] + results = TestOnTestData()(data, data, learners) + + self.assertEqual(results.predicted.shape, (2, len(data))) + np.testing.assert_equal(results.predicted, np.ones((2, 100))) + probs = results.probabilities + self.assertTrue((probs[:, :, 0] < probs[:, :, 2]).all()) + self.assertTrue((probs[:, :, 2] < probs[:, :, 1]).all()) + + train = self.iris[50:120] + test = self.iris[:50] + results = TestOnTestData()(train, test, learners) + self.assertEqual(results.predicted.shape, (2, len(test))) + np.testing.assert_equal(results.predicted, np.ones((2, 50))) + probs = results.probabilities + self.assertTrue((probs[:, :, 0] == 0).all()) + + def test_store_data(self): + data = self.random_table + train = data[:int(self.nrows*.75)] + test = data[int(self.nrows*.75):] + learners = [MajorityLearner()] + + res = TestOnTestData()(train, test, learners) + self.assertIsNone(res.data) + + res = TestOnTestData(store_data=True)(train, test, learners) + self.assertIs(res.data, test) + + def test_store_models(self): + data = self.random_table + train = data[:int(self.nrows*.75)] + test = data[int(self.nrows*.75):] + learners = [NaiveBayesLearner(), MajorityLearner()] + + res = TestOnTestData()(train, test, learners) + self.assertIsNone(res.models) + + res = TestOnTestData(store_models=True)(train, test, learners) + self.check_models(res, learners, 1) + + @staticmethod + def test_miss_majority(): + x = np.zeros((50, 3)) + y = x[:, -1] + x[49] = 1 + data = Table.from_numpy(None, x, y) + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[49] = 0 + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0][:49], 0) + + x[25:] = 1 + y = x[:, -1] + data = Table.from_numpy(None, x, y) + res = TestOnTrainingData()(data, [MajorityLearner()]) + np.testing.assert_equal(res.predicted[0], res.predicted[0][0]) + + def run_test_failed(self, method, succ_calls): + # Can't use mocking helpers here (wrong result type for Majority, + # exception caught for fails) + def major(*args): + nonlocal major_call + major_call += 1 + return MajorityLearner()(*args) + + def fails(_): + nonlocal fail_calls + fail_calls += 1 + raise SystemError("failing learner") + + major_call = 0 + fail_calls = 0 + data = random_data(50, 4) + res = TestOnTestData()(data, data, [major, fails, major]) + self.assertFalse(res.failed[0]) + self.assertIsInstance(res.failed[1], Exception) + self.assertFalse(res.failed[2]) + self.assertEqual(major_call, 2) + self.assertEqual(fail_calls, 1) + + def test_callback(self): + def record_progress(p): + progress.append(p) + + progress = [] + data = random_data(50, 4) + TestOnTestData()(data, data, [MajorityLearner(), MajorityLearner()], + callback=record_progress) + np.testing.assert_almost_equal(progress, self._callback_values(2)) + + def test_preprocessor(self): + def preprocessor(data): + data_sizes.append(len(data)) + return data + + data_sizes = [] + data = random_data(50, 5) + TestOnTestData()(data[:30], data[-20:], + [MajorityLearner(), MajorityLearner()], + preprocessor=preprocessor) + self.assertEqual(data_sizes, [30]) + + @patch("Orange.evaluation.testing.Validation.__new__") + def test_train_data_argument(self, validation_new): + data = Mock() + test_data = Mock() + TestOnTestData(data, test_data) + args = validation_new.call_args[1] + self.assertIs(args["data"], data) + self.assertIs(args["test_data"], test_data) + validation_new.reset_mock() + + TestOnTestData(test_data=test_data, train_data=data) + args = validation_new.call_args[1] + self.assertIs(args["data"], data) + self.assertIs(args["test_data"], test_data) + validation_new.reset_mock() + + self.assertRaises( + ValueError, + TestOnTestData, data, train_data=data, test_data=test_data) + + +class TestTrainTestSplit(unittest.TestCase): + def test_fixed_training_size(self): + data = Table("iris") + train, test = sample(data, 100) + self.assertEqual(len(train), 100) + self.assertEqual(len(train) + len(test), len(data)) + + train, test = sample(data, 0.1) + self.assertEqual(len(train), 15) + self.assertEqual(len(train) + len(test), len(data)) + + train, test = sample(data, 0.1, stratified=True) + self.assertEqual(len(train), 15) + self.assertEqual(len(train) + len(test), len(data)) + + train, test = sample(data, 0.2, replace=True) + self.assertEqual(len(train), 30) + + train, test = sample(data, 0.9, replace=True) + self.assertEqual(len(train), 135) + self.assertGreater(len(train) + len(test), len(data)) + + +class TestShuffleSplit(TestSampling): + def test_init(self): + res = ShuffleSplit(n_resamples=1, train_size=0.1, test_size=0.2, + stratified=False, random_state=42) + self.assertEqual(res.n_resamples, 1) + self.assertEqual(res.train_size, 0.1) + self.assertEqual(res.test_size, 0.2) + self.assertFalse(res.stratified) + self.assertEqual(res.random_state, 42) + + def test_results(self): + data = self.random_table + train_size, n_resamples = 0.6, 10 + res = ShuffleSplit( + train_size=train_size, test_size=1 - train_size, + n_resamples=n_resamples)(data, [NaiveBayesLearner()]) + self.assertEqual(len(res.predicted[0]), + n_resamples * self.nrows * (1 - train_size)) + + def test_stratified(self): + # strata size + n = 50 + res = ShuffleSplit( + train_size=.5, test_size=.5, n_resamples=3, stratified=True, + random_state=0)(self.iris, [NaiveBayesLearner()]) + + for fold in res.folds: + self.assertEqual(np.count_nonzero(res.row_indices[fold] < n), n // 2) + self.assertEqual(np.count_nonzero(res.row_indices[fold] < 2 * n), n) + + def test_not_stratified(self): + # strata size + n = 50 + res = ShuffleSplit( + train_size=.5, test_size=.5, n_resamples=3, stratified=False, + random_state=0)(self.iris, [NaiveBayesLearner()]) + + strata_samples = [] + for fold in res.folds: + strata_samples += [ + np.count_nonzero(res.row_indices[fold] < n) == n // 2, + np.count_nonzero(res.row_indices[fold] < 2 * n) == n] + + self.assertTrue(not all(strata_samples)) + + +class TestResults(unittest.TestCase): + def setUp(self): + self.data = Table("iris") + self.actual = np.zeros(100) + self.row_indices = np.arange(100) + self.folds = (range(50), range(10, 60)), (range(50, 100), range(50)) + self.learners = [MajorityLearner(), MajorityLearner()] + self.models = np.array([[Mock(), Mock()]]) + self.predicted = np.zeros((2, 100)) + self.probabilities = np.zeros((2, 100, 3)) + self.failed = [False, True] + + def test_store_attributes(self): + res = Results( + self.data, + row_indices=self.row_indices, folds=self.folds, + score_by_folds=False, learners=self.learners, models=self.models, + failed=self.failed, actual=self.actual, predicted=self.predicted, + probabilities=self.probabilities, store_data=42, store_models=43) + self.assertIs(res.data, self.data) + self.assertEqual(res.nrows, 100) + self.assertIs(res.row_indices, self.row_indices) + self.assertIs(res.folds, self.folds) + self.assertFalse(res.score_by_folds) + self.assertIs(res.learners, self.learners) + self.assertIs(res.models, self.models) + self.assertIs(res.failed, self.failed) + self.assertIs(res.actual, self.actual) + self.assertIs(res.predicted, self.predicted) + self.assertIs(res.probabilities, self.probabilities) + + def test_guess_sizes(self): + res = Results(self.data, actual=self.actual) + self.assertEqual(res.nrows, 100) + self.assertIsNone(res.row_indices) + self.assertIsNone(res.predicted) + self.assertIsNone(res.probabilities) + self.assertIsNone(res.models) + self.assertIsNone(res.failed) + + res = Results(self.data, models=self.models) + self.assertIsNone(res.nrows) + self.assertIsNone(res.predicted) + self.assertIsNone(res.probabilities) + self.assertIs(res.models, self.models) + self.assertEqual(res.failed, [False, False]) + + res = Results(self.data, actual=self.actual, learners=self.learners) + self.assertIs(res.data, self.data) + self.assertIsNone(res.row_indices) + self.assertEqual(res.nrows, 100) + self.assertIsNone(res.folds, self.folds) + self.assertEqual(res.predicted.shape, (2, 100)) + self.assertEqual(res.probabilities.shape, (2, 100, 3)) + self.assertEqual(res.failed, [False, False]) + + res = Results(nrows=100, nmethods=2, nclasses=3) + self.assertIsNone(res.data) + self.assertIsNone(res.row_indices) + self.assertIsNone(res.folds, self.folds) + self.assertEqual(res.nrows, 100) + self.assertEqual(res.predicted.shape, (2, 100)) + self.assertEqual(res.probabilities.shape, (2, 100, 3)) + self.assertEqual(res.failed, [False, False]) + + def test_check_consistency_domain(self): + self.assertRaises( + ValueError, + Results, self.data, domain=Domain([], [])) + + def test_check_consistency_nrows(self): + self.assertRaises( + ValueError, + Results, nrows=10, actual=self.actual) + self.assertRaises( + ValueError, + Results, nrows=10, row_indices=self.row_indices) + self.assertRaises( + ValueError, + Results, actual=self.actual, row_indices=self.row_indices[:5]) + self.assertRaises( + ValueError, + Results, nrows=10, predicted=self.predicted) + self.assertRaises( + ValueError, + Results, nrows=10, probabilities=self.probabilities) + + def test_check_consistency_nclasses(self): + self.assertRaises( + ValueError, + Results, self.data, nclasses=10) + self.assertRaises( + ValueError, + Results, domain=self.data.domain, nclasses=10) + self.assertRaises( + ValueError, + Results, + nclasses=10, + probabilities=self.probabilities, learners=self.learners, nrows=100) + + attributes = self.data.domain.attributes + reg_domain = Domain(attributes[:3], attributes[3]) + self.assertRaises( + ValueError, + Results, nclasses=5, domain=self.data.domain) + self.assertRaises( + ValueError, + Results, nclasses=5, probabilities=self.probabilities) + self.assertRaises( + ValueError, + Results, nclasses=5, domain=reg_domain) + self.assertRaises( + ValueError, + Results, domain=reg_domain, probabilities=self.probabilities) + + def test_check_consistency_nmethods(self): + self.assertRaises( + ValueError, + Results, nmethods=10, learners=self.learners) + self.assertRaises( + ValueError, + Results, nmethods=10, models=self.models) + self.assertRaises( + ValueError, + Results, nmethods=10, failed=self.failed) + self.assertRaises( + ValueError, + Results, nmethods=10, predicted=self.predicted) + self.assertRaises( + ValueError, + Results, nmethods=10, probabilities=self.probabilities) + self.assertRaises( + ValueError, + Results, + probabilities=self.probabilities[:1], predicted=self.predicted) diff --git a/pyminer2/tests/test_filter.py b/pyminer2/tests/test_filter.py new file mode 100644 index 0000000000000000000000000000000000000000..325b4ae6d3ae0c7199c5cd7cf879d804fefcb72e --- /dev/null +++ b/pyminer2/tests/test_filter.py @@ -0,0 +1,462 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import MagicMock, patch +import itertools + +import numpy as np + +from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable +from Orange.data.filter import \ + FilterContinuous, FilterDiscrete, FilterString, Values, HasClass, \ + IsDefined, SameValue, Random, ValueFilter, FilterStringList, FilterRegex +from Orange.tests import test_filename + +NIMOCK = MagicMock(side_effect=NotImplementedError()) + + +class TestFilterValues(unittest.TestCase): + def setUp(self): + self.iris = Table('iris') + + @patch("Orange.data.Table._filter_values", NIMOCK) + def test_values(self): + vs = self.iris.domain.variables + f1 = FilterContinuous(vs[0], FilterContinuous.Less, 5) + f2 = FilterContinuous(vs[1], FilterContinuous.Greater, 3) + f3 = FilterDiscrete(vs[4], [2]) + f12 = Values([f1, f2], conjunction=False, negate=True) + f123 = Values([f12, f3]) + d12 = f12(self.iris) + d123 = f123(self.iris) + self.assertGreater(len(d12), len(d123)) + self.assertTrue((d123.X[:, 0] >= 5).all()) + self.assertTrue((d123.X[:, 1] <= 3).all()) + self.assertTrue((d123.Y == 2).all()) + self.assertEqual(len(d123), + (~((self.iris.X[:, 0] < 5) | (self.iris.X[:, 1] > 3)) & + (self.iris.Y == 2)).sum()) + + +class TestIsDefinedFilter(unittest.TestCase): + def setUp(self): + self.table = Table(test_filename('datasets/imports-85.tab')) + self.n_missing = 46 + self.assertTrue(self.table.has_missing()) + + def test_is_defined_filter_table(self): + filter_ = IsDefined() + without_missing = filter_(self.table) + self.assertEqual(len(without_missing), + len(self.table) - self.n_missing) + self.assertFalse(without_missing.has_missing()) + + filter_ = IsDefined(negate=True) + just_missing = filter_(self.table) + self.assertEqual(len(just_missing), self.n_missing) + self.assertTrue(just_missing.has_missing()) + + def test_is_defined_filter_instance(self): + instance_with_missing = self.table[0] + instance_without_missing = self.table[3] + + filter_ = IsDefined() + self.assertFalse(filter_(instance_with_missing)) + self.assertTrue(filter_(instance_without_missing)) + + filter_ = IsDefined(negate=True) + self.assertTrue(filter_(instance_with_missing)) + self.assertFalse(filter_(instance_without_missing)) + + @patch('Orange.data.Table._filter_is_defined', NIMOCK) + def test_is_defined_filter_not_implemented(self): + self.test_is_defined_filter_table() + + +class TestHasClassFilter(unittest.TestCase): + def setUp(self): + self.table = Table(test_filename('datasets/imports-85.tab')) + self.n_missing = 4 + self.assertTrue(self.table.has_missing_class()) + + def test_has_class_filter_table(self): + filter_ = HasClass() + with_class = filter_(self.table) + self.assertEqual(len(with_class), + len(self.table) - self.n_missing) + self.assertFalse(with_class.has_missing_class()) + + filter_ = HasClass(negate=True) + without_class = filter_(self.table) + self.assertEqual(len(without_class), self.n_missing) + self.assertTrue(without_class.has_missing_class()) + + def test_has_class_multiclass(self): + domain = Domain([DiscreteVariable("x", values="01")], + [DiscreteVariable("y1", values="01"), + DiscreteVariable("y2", values="01")]) + table = Table.from_list(domain, [[0, 1, np.nan], + [1, np.nan, 0], + [1, 0, 1], + [1, np.nan, np.nan]]) + table = HasClass()(table) + self.assertTrue(not np.isnan(table).any()) + self.assertEqual(table.domain, domain) + self.assertEqual(len(table), 1) + + def test_has_class_filter_instance(self): + class_missing = self.table[9] + class_present = self.table[0] + + filter_ = HasClass() + self.assertFalse(filter_(class_missing)) + self.assertTrue(filter_(class_present)) + + filter_ = HasClass(negate=True) + self.assertTrue(filter_(class_missing)) + self.assertFalse(filter_(class_present)) + + @patch('Orange.data.Table._filter_has_class', NIMOCK) + def test_has_class_filter_not_implemented(self): + self.test_has_class_filter_table() + + +class TestFilterContinuous(unittest.TestCase): + def setUp(self): + self.domain = Domain([ContinuousVariable(x) for x in "abcd"]) + self.inst = Table(self.domain, np.array([[0.1, 0.2, 0.3, np.nan]]))[0] + + def test_min(self): + flt = FilterContinuous(1, FilterContinuous.Between, 1, 2) + self.assertEqual(flt.min, 1) + self.assertEqual(flt.max, 2) + self.assertEqual(flt.ref, 1) + + flt.ref = 0 + self.assertEqual(flt.min, 0) + + flt.min = -1 + self.assertEqual(flt.ref, -1) + + self.assertRaises( + TypeError, + FilterContinuous, 1, FilterContinuous.Equal, 0, c=12) + self.assertRaises( + TypeError, + FilterContinuous, 1, FilterContinuous.Equal, 0, min=5, c=12) + + flt = FilterContinuous(1, FilterContinuous.Between, min=1, max=2) + self.assertEqual(flt.ref, 1) + + def test_operator(self): + inst = self.inst + flt = FilterContinuous + self.assertTrue(flt(1, flt.Equal, 0.2)(inst)) + self.assertFalse(flt(1, flt.Equal, 0.3)(inst)) + + self.assertTrue(flt(1, flt.NotEqual, 0.3)(inst)) + self.assertFalse(flt(1, flt.NotEqual, 0.2)(inst)) + + self.assertTrue(flt(1, flt.Less, 0.3)(inst)) + self.assertFalse(flt(1, flt.Less, 0.2)(inst)) + + self.assertTrue(flt(1, flt.LessEqual, 0.3)(inst)) + self.assertTrue(flt(1, flt.LessEqual, 0.2)(inst)) + self.assertFalse(flt(1, flt.LessEqual, 0.1)(inst)) + + self.assertTrue(flt(1, flt.Greater, 0.1)(inst)) + self.assertFalse(flt(1, flt.Greater, 0.2)(inst)) + + self.assertTrue(flt(1, flt.GreaterEqual, 0.1)(inst)) + self.assertTrue(flt(1, flt.GreaterEqual, 0.2)(inst)) + self.assertFalse(flt(1, flt.GreaterEqual, 0.3)(inst)) + + self.assertTrue(flt(1, flt.Between, 0.05, 0.4)(inst)) + self.assertTrue(flt(1, flt.Between, 0.2, 0.4)(inst)) + self.assertTrue(flt(1, flt.Between, 0.05, 0.2)(inst)) + self.assertFalse(flt(1, flt.Between, 0.3, 0.4)(inst)) + + self.assertFalse(flt(1, flt.Outside, 0.05, 0.4)(inst)) + self.assertFalse(flt(1, flt.Outside, 0.2, 0.4)(inst)) + self.assertFalse(flt(1, flt.Outside, 0.05, 0.2)(inst)) + self.assertTrue(flt(1, flt.Outside, 0.3, 0.4)(inst)) + + self.assertTrue(flt(1, flt.IsDefined)(inst)) + self.assertFalse(flt(3, flt.IsDefined)(inst)) + + self.assertRaises(ValueError, flt(1, -1, 1), inst) + + def test_position(self): + inst = self.inst + flt = FilterContinuous + self.assertFalse(flt(0, flt.Equal, 0.2)(inst)) + self.assertTrue(flt(1, flt.Equal, 0.2)(inst)) + self.assertFalse(flt(2, flt.Equal, 0.2)(inst)) + self.assertFalse(flt(3, flt.Equal, 0.2)(inst)) + + self.assertFalse(flt("a", flt.Equal, 0.2)(inst)) + self.assertTrue(flt("b", flt.Equal, 0.2)(inst)) + self.assertFalse(flt("c", flt.Equal, 0.2)(inst)) + self.assertFalse(flt("d", flt.Equal, 0.2)(inst)) + + a, b, c, d = self.domain.attributes + self.assertFalse(flt(a, flt.Equal, 0.2)(inst)) + self.assertTrue(flt(b, flt.Equal, 0.2)(inst)) + self.assertFalse(flt(c, flt.Equal, 0.2)(inst)) + self.assertFalse(flt(d, flt.Equal, 0.2)(inst)) + + def test_nan(self): + inst = self.inst + flt = FilterContinuous + + self.assertFalse(flt(3, flt.Equal, 0.3)(inst)) + self.assertFalse(flt(3, flt.NotEqual, 0.3)(inst)) + self.assertFalse(flt(3, flt.Less, 0.2)(inst)) + self.assertFalse(flt(3, flt.LessEqual, 0.1)(inst)) + self.assertFalse(flt(3, flt.Greater, 0.2)(inst)) + self.assertFalse(flt(3, flt.GreaterEqual, 0.1)(inst)) + self.assertFalse(flt(3, flt.Between, 0.05, 0.4)(inst)) + self.assertFalse(flt(3, flt.Outside, 0.05, 0.4)(inst)) + + self.assertTrue(flt(3, flt.Equal, np.nan)(inst)) + self.assertFalse(flt(3, flt.NotEqual, np.nan)(inst)) + + def test_str(self): + flt = FilterContinuous(1, FilterContinuous.Equal, 1) + + self.assertEqual(str(flt), "feature(1) = 1") + + flt = FilterContinuous("foo", FilterContinuous.Equal, 1) + self.assertEqual(str(flt), "foo = 1") + + flt = FilterContinuous(self.domain[0], FilterContinuous.Equal, 1, 2) + self.assertEqual(str(flt), "a = 1") + + flt.oper = flt.NotEqual + self.assertEqual(str(flt), "a ≠ 1") + + flt.oper = flt.Less + self.assertEqual(str(flt), "a < 1") + + flt.oper = flt.LessEqual + self.assertEqual(str(flt), "a ≤ 1") + + flt.oper = flt.Greater + self.assertEqual(str(flt), "a > 1") + + flt.oper = flt.GreaterEqual + self.assertEqual(str(flt), "a ≥ 1") + + flt.oper = flt.Between + self.assertEqual(str(flt), "1 ≤ a ≤ 2") + + flt.oper = flt.Outside + self.assertEqual(str(flt), "not 1 ≤ a ≤ 2") + + flt.oper = flt.IsDefined + self.assertEqual(str(flt), "a is defined") + + flt.oper = -1 + self.assertEqual(str(flt), "invalid operator") + + def test_eq(self): + flt1 = FilterContinuous(1, FilterContinuous.Between, 1, 2) + flt2 = FilterContinuous(1, FilterContinuous.Between, 1, 2) + flt3 = FilterContinuous(1, FilterContinuous.Between, 1, 3) + self.assertEqual(flt1, flt2) + self.assertNotEqual(flt1, flt3) + self.assertEqual(flt1.__dict__ == flt2.__dict__, flt1 == flt2) + self.assertEqual(flt1.__dict__ == flt3.__dict__, flt1 == flt3) + + +class TestFilterDiscrete(unittest.TestCase): + def test_eq(self): + flt1 = FilterDiscrete(1, None) + flt2 = FilterDiscrete(1, None) + flt3 = FilterDiscrete(2, None) + self.assertEqual(flt1, flt2) + self.assertEqual(flt1.__dict__ == flt2.__dict__, flt1 == flt2) + self.assertNotEqual(flt1, flt3) + self.assertEqual(flt1.__dict__ == flt3.__dict__, flt1 == flt3) + + +class TestFilterString(unittest.TestCase): + + def setUp(self): + self.data = Table("zoo") + self.inst = self.data[0] # aardvark + + def test_case_sensitive(self): + flt = FilterString("name", FilterString.Equal, "Aardvark", case_sensitive=True) + self.assertFalse(flt(self.inst)) + flt = FilterString("name", FilterString.Equal, "Aardvark", case_sensitive=False) + self.assertTrue(flt(self.inst)) + + def test_operators(self): + flt = FilterString("name", FilterString.Equal, "aardvark") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Equal, "bass") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.NotEqual, "bass") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.NotEqual, "aardvark") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.Less, "bass") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Less, "aa") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.LessEqual, "bass") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.LessEqual, "aardvark") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.LessEqual, "aa") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.Greater, "aa") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Greater, "aardvark") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.GreaterEqual, "aa") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.GreaterEqual, "aardvark") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.GreaterEqual, "bass") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.Between, "aa", "aardvark") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Between, "a", "aa") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.Outside, "aaz", "bass") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Outside, "aardvark", "bass") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.Contains, "ard") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.Contains, "ra") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.StartsWith, "aar") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.StartsWith, "ard") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.EndsWith, "aardvark") + self.assertTrue(flt(self.inst)) + flt = FilterString("name", FilterString.EndsWith, "aard") + self.assertFalse(flt(self.inst)) + + flt = FilterString("name", FilterString.IsDefined) + self.assertTrue(flt(self.inst)) + for s in ["?", "nan"]: + self.inst["name"] = s + flt = FilterString("name", FilterString.IsDefined) + self.assertTrue(flt(self.inst)) + self.inst["name"] = "" + flt = FilterString("name", FilterString.IsDefined) + self.assertFalse(flt(self.inst)) + + +class TestSameValueFilter(unittest.TestCase): + def setUp(self): + self.table = Table('zoo') + + self.attr_disc = self.table.domain["type"] + self.attr_cont = self.table.domain["legs"] + self.attr_meta = self.table.domain["name"] + + self.value_cont = 4 + self.value_disc = self.attr_disc.to_val("mammal") + self.value_meta = self.attr_meta.to_val("girl") + + def test_same_value_filter_table(self): + + test_pairs = ((self.attr_cont, 4, self.value_cont), + (self.attr_disc, "mammal", self.value_disc), + (self.attr_meta, "girl", self.value_meta),) + + for var_index, value, num_value in test_pairs: + filter_ = SameValue(var_index, value)(self.table) + self.assertTrue(all(inst[var_index] == num_value for inst in filter_)) + + filter_inverse = SameValue(var_index, value, negate=True)(self.table) + self.assertTrue(all(inst[var_index] != num_value for inst in filter_inverse)) + + self.assertEqual(len(filter_) + len(filter_inverse), len(self.table)) + + + for t1, t2 in itertools.combinations(test_pairs, 2): + pos1, val1, r1 = t1 + pos2, val2, r2 = t2 + + filter_1 = SameValue(pos1, val1)(self.table) + filter_2 = SameValue(pos2, val2)(self.table) + + filter_12 = SameValue(pos2, val2)(SameValue(pos1, val1)(self.table)) + filter_21 = SameValue(pos1, val1)(SameValue(pos2, val2)(self.table)) + + self.assertEqual(len(filter_21), len(filter_12)) + + self.assertTrue(len(filter_1) >= len(filter_12)) + self.assertTrue(len(filter_2) >= len(filter_12)) + + self.assertTrue(all(inst[pos1] == r1 and + inst[pos2] == r2 and + inst in filter_21 + for inst in filter_12)) + self.assertTrue(all(inst[pos1] == r1 and + inst[pos2] == r2 and + inst in filter_12 + for inst in filter_21)) + + def test_same_value_filter_instance(self): + inst = self.table[0] + + filter_ = SameValue(self.attr_disc, self.value_disc)(inst) + self.assertEqual(filter_, inst[self.attr_disc] == self.value_disc) + + filter_n = SameValue(self.attr_disc, self.value_disc, negate=True)(inst) + self.assertEqual(filter_n, inst[self.attr_disc] != self.value_disc) + + @patch('Orange.data.Table._filter_same_value', NIMOCK) + def test_has_class_filter_not_implemented(self): + self.test_same_value_filter_table() + + +class TestFilterReprs(unittest.TestCase): + def setUp(self): + self.table = Table('zoo') + self.attr_disc = self.table.domain["type"] + self.value_disc = self.attr_disc.to_val("mammal") + self.vs = self.table.domain.variables + + self.table2 = Table("zoo") + self.inst = self.table2[0] # aardvark + + def test_reprs(self): + flid = IsDefined(negate=True) + flhc = HasClass() + flr = Random() + fld = FilterDiscrete(self.attr_disc, None) + flsv = SameValue(self.attr_disc, self.value_disc, negate=True) + flc = FilterContinuous(self.vs[0], FilterContinuous.Less, 5) + flc2 = FilterContinuous(self.vs[1], FilterContinuous.Greater, 3) + flv = Values([flc, flc2], conjunction=False, negate=True) + flvf = ValueFilter(self.attr_disc) + fls = FilterString("name", FilterString.Equal, "Aardvark", case_sensitive=False) + flsl = FilterStringList("name", ["Aardvark"], case_sensitive=False) + flrx = FilterRegex("name", "^c...$") + + filters = [flid, flhc, flr, fld, flsv, flc, flv, flvf, fls, flsl, flrx] + + for f in filters: + repr_str = repr(f) + new_f = eval(repr_str) + self.assertEqual(repr(new_f), repr_str) diff --git a/pyminer2/tests/test_fitter.py b/pyminer2/tests/test_fitter.py new file mode 100644 index 0000000000000000000000000000000000000000..c3aa03993a57d58d0077dc540f5413d16515fab6 --- /dev/null +++ b/pyminer2/tests/test_fitter.py @@ -0,0 +1,169 @@ +import unittest +from unittest.mock import Mock + +from Orange.classification.base_classification import LearnerClassification +from Orange.data import Table, ContinuousVariable +from Orange.modelling import Fitter +from Orange.preprocess import Randomize, Discretize +from Orange.regression.base_regression import LearnerRegression + + +class DummyClassificationLearner(LearnerClassification): + pass + + +class DummyRegressionLearner(LearnerRegression): + pass + + +class DummyFitter(Fitter): + name = 'dummy' + __fits__ = {'classification': DummyClassificationLearner, + 'regression': DummyRegressionLearner} + + +class FitterTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.heart_disease = Table('heart_disease') + cls.housing = Table('housing') + + def test_dispatches_to_correct_learner(self): + """Based on the input data, it should dispatch the fitting process to + the appropriate learner""" + DummyClassificationLearner.fit = Mock() + DummyRegressionLearner.fit = Mock() + fitter = DummyFitter() + + fitter(self.heart_disease) + self.assertEqual( + DummyClassificationLearner.fit.call_count, 1, + 'Classification learner was never called for classification' + 'problem') + self.assertEqual( + DummyRegressionLearner.fit.call_count, 0, + 'Regression learner was called for classification problem') + + DummyClassificationLearner.fit.reset_mock() + DummyRegressionLearner.fit.reset_mock() + + fitter(self.housing) + self.assertEqual( + DummyRegressionLearner.fit.call_count, 1, + 'Regression learner was never called for regression problem') + self.assertEqual( + DummyClassificationLearner.fit.call_count, 0, + 'Classification learner was called for regression problem') + + def test_constructs_learners_with_appropriate_parameters(self): + """In case the classification and regression learners require different + parameters, the fitter should be able to determine which ones have to + be passed where""" + + class DummyClassificationLearner(LearnerClassification): + def __init__(self, classification_param=1, **_): + super().__init__() + self.param = classification_param + + class DummyRegressionLearner(LearnerRegression): + def __init__(self, regression_param=2, **_): + super().__init__() + self.param = regression_param + + class DummyFitter(Fitter): + __fits__ = {'classification': DummyClassificationLearner, + 'regression': DummyRegressionLearner} + + # Prevent fitting error from being thrown + DummyClassificationLearner.fit = Mock() + DummyRegressionLearner.fit = Mock() + + # Test without passing any params + fitter = DummyFitter() + self.assertEqual(fitter.get_learner(Fitter.CLASSIFICATION).param, 1) + self.assertEqual(fitter.get_learner(Fitter.REGRESSION).param, 2) + + # Pass specific params + try: + fitter = DummyFitter(classification_param=10, regression_param=20) + self.assertEqual(fitter.get_learner(Fitter.CLASSIFICATION).param, 10) + self.assertEqual(fitter.get_learner(Fitter.REGRESSION).param, 20) + except TypeError: + self.fail('Fitter did not properly distribute params to learners') + + def test_correctly_sets_preprocessors_on_learner(self): + """Fitters have to be able to pass the `use_default_preprocessors` and + preprocessors down to individual learners""" + pp = Randomize() + fitter = DummyFitter(preprocessors=pp) + fitter.use_default_preprocessors = True + learner = fitter.get_learner(Fitter.CLASSIFICATION) + + self.assertEqual( + learner.use_default_preprocessors, True, + 'Fitter did not properly pass the `use_default_preprocessors`' + 'attribute to its learners') + self.assertEqual( + tuple(learner.active_preprocessors), (pp,), + 'Fitter did not properly pass its preprocessors to its learners') + + def test_properly_delegates_preprocessing(self): + class DummyClassificationLearner(LearnerClassification): + preprocessors = [Discretize()] + + def __init__(self, classification_param=1, **_): + super().__init__() + self.param = classification_param + + class DummyFitter(Fitter): + __fits__ = {'classification': DummyClassificationLearner, + 'regression': DummyRegressionLearner} + + data = self.heart_disease + fitter = DummyFitter() + # Sanity check + self.assertTrue(any( + isinstance(v, ContinuousVariable) for v in data.domain.variables)) + # Preprocess the data and check that the discretization was applied + pp_data = fitter.preprocess(self.heart_disease) + self.assertTrue(not any( + isinstance(v, ContinuousVariable) for v in pp_data.domain.variables)) + + def test_default_kwargs_with_change_kwargs(self): + """Fallback to default args in case specialized params not specified. + """ + class DummyClassificationLearner(LearnerClassification): + def __init__(self, param='classification_default', **_): + super().__init__() + self.param = param + + def fit_storage(self, data): + return DummyModel(self.param) + + class DummyRegressionLearner(LearnerRegression): + def __init__(self, param='regression_default', **_): + super().__init__() + self.param = param + + def fit_storage(self, data): + return DummyModel(self.param) + + class DummyModel: + def __init__(self, param): + self.param = param + + class DummyFitter(Fitter): + __fits__ = {'classification': DummyClassificationLearner, + 'regression': DummyRegressionLearner} + + def _change_kwargs(self, kwargs, problem_type): + if problem_type == self.CLASSIFICATION: + kwargs['param'] = kwargs.get('classification_param') + else: + kwargs['param'] = kwargs.get('regression_param') + return kwargs + + learner = DummyFitter() + iris, housing = Table('iris')[:5], Table('housing')[:5] + self.assertEqual(learner(iris).param, 'classification_default') + self.assertEqual(learner(housing).param, 'regression_default') diff --git a/pyminer2/tests/test_freeviz.py b/pyminer2/tests/test_freeviz.py new file mode 100644 index 0000000000000000000000000000000000000000..4e07119359b22ae24c1f9eaef18b81e07397181a --- /dev/null +++ b/pyminer2/tests/test_freeviz.py @@ -0,0 +1,96 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np + +from Orange.data import Table +from Orange.preprocess import Continuize +from Orange.projection import FreeViz + + +class TestFreeviz(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table("iris") + cls.housing = Table("housing") + cls.zoo = Table("zoo") + + def test_basic(self): + table = self.iris.copy() + table[3, 3] = np.nan + freeviz = FreeViz() + model = freeviz(table) + proj = model(table) + self.assertEqual(len(proj), len(table)) + self.assertTrue(np.isnan(proj.X).any()) + np.testing.assert_array_equal(proj[:100], model(table[:100])) + + def test_regression(self): + table = Table("housing")[::10] + freeviz = FreeViz() + freeviz(table) + + freeviz = FreeViz(p=2) + freeviz(table) + + @unittest.skip("Test weights is too slow.") + def test_weights(self): + table = Table("iris") + weights = np.random.rand(150, 1).flatten() + freeviz = FreeViz(weights=weights, p=3, scale=False, center=False) + freeviz(table) + + scale = np.array([0.5, 0.4, 0.6, 0.8]) + freeviz = FreeViz(scale=scale, center=[0.2, 0.6, 0.4, 0.2]) + freeviz(table) + + def test_raising_errors(self): + table = Table("iris") + + scale = np.array([0.5, 0.4, 0.6]) + freeviz = FreeViz(scale=scale) + self.assertRaises(ValueError, freeviz, table) + + freeviz = FreeViz(center=[0.6, 0.4, 0.2]) + self.assertRaises(ValueError, freeviz, table) + + weights = np.random.rand(100, 1).flatten() + freeviz = FreeViz(weights=weights) + self.assertRaises(ValueError, freeviz, table) + + table = Table("titanic")[::10] + freeviz = FreeViz() + self.assertRaises(ValueError, freeviz, table) + + def test_initial(self): + FreeViz.init_radial(1) + FreeViz.init_radial(2) + FreeViz.init_radial(3) + FreeViz.init_random(2, 4, 5) + + def test_transform_changed_domain(self): + """ + 1. Open data, apply some preprocessor, splits the data into two parts, + use FreeViz on the first part, and then transform the second part. + + 2. Open data, split into two parts, apply the same preprocessor and + FreeViz only on the first part, and then transform the second part. + + The transformed second part in (1) and (2) has to be the same. + """ + data = Table("titanic")[::10] + normalize = Continuize() + freeviz = FreeViz(maxiter=40) + + # normalize all + ndata = normalize(data) + model = freeviz(ndata[:100]) + result_1 = model(ndata[100:]) + + # normalize only the "training" part + ndata = normalize(data[:100]) + model = freeviz(ndata) + result_2 = model(data[100:]) + + np.testing.assert_almost_equal(result_1.X, result_2.X) diff --git a/pyminer2/tests/test_fss.py b/pyminer2/tests/test_fss.py new file mode 100644 index 0000000000000000000000000000000000000000..87565f2714570de33168b7c55983c90eee1a5da0 --- /dev/null +++ b/pyminer2/tests/test_fss.py @@ -0,0 +1,111 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table, Variable +from Orange.preprocess.score import ANOVA, Gini, UnivariateLinearRegression, \ + Chi2 +from Orange.preprocess import SelectBestFeatures, Impute, SelectRandomFeatures +from Orange.tests import test_filename + + +class TestFSS(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.titanic = Table('titanic') + cls.heart_disease = Table('heart_disease') + cls.iris = Table('iris') + cls.imports = Table(test_filename('datasets/imports-85.tab')) + + def test_select_1(self): + gini = Gini() + s = SelectBestFeatures(method=gini, k=1) + data2 = s(self.titanic) + best = max((gini(self.titanic, f), f) for f in self.titanic.domain.attributes)[1] + self.assertEqual(data2.domain.attributes[0], best) + + def test_select_2(self): + gini = Gini() + # 100th percentile = selection of top1 attribute + sel1 = SelectBestFeatures(method=gini, k=1.0) + data2 = sel1(self.titanic) + best = max((gini(self.titanic, f), f) for f in self.titanic.domain.attributes)[1] + self.assertEqual(data2.domain.attributes[0], best) + + # no k and no threshold, select all attributes + sel2 = SelectBestFeatures(method=gini, k=0) + data2 = sel2(self.titanic) + self.assertEqual(len(data2.domain.attributes), len(self.titanic.domain.attributes)) + + # 31% = selection of top (out of 3) attributes + sel3 = SelectBestFeatures(method=gini, k=0.31) + data2 = sel3(self.titanic) + self.assertEqual(len(data2.domain.attributes), 1) + + # 35% = selection of top (out of 3) attributes + sel3 = SelectBestFeatures(method=gini, k=0.35) + data2 = sel3(self.titanic) + self.assertEqual(len(data2.domain.attributes), 1) + + # 1% = select one (out of 3) attributes + sel3 = SelectBestFeatures(method=gini, k=0.01) + data2 = sel3(self.titanic) + self.assertEqual(len(data2.domain.attributes), 1) + + # number of selected attrs should be relative to number of current input attrs + sel3 = SelectBestFeatures(method=gini, k=1.0) + data2 = sel3(self.heart_disease) + self.assertEqual(len(data2.domain.attributes), 13) + + def test_select_threshold(self): + anova = ANOVA() + t = 30 + data2 = SelectBestFeatures(method=anova, threshold=t)(self.heart_disease) + self.assertTrue(all(anova(self.heart_disease, f) >= t + for f in data2.domain.attributes)) + + def test_error_when_using_regression_score_on_classification_data(self): + s = SelectBestFeatures(method=UnivariateLinearRegression(), k=3) + with self.assertRaises(ValueError): + s(self.heart_disease) + + def test_discrete_scores_on_continuous_features(self): + c = self.iris.columns + for method in (Gini(), Chi2()): + d1 = SelectBestFeatures(method=method)(self.iris) + expected = \ + (c.petal_length, c.petal_width, c.sepal_length, c.sepal_width) + self.assertSequenceEqual(d1.domain.attributes, expected) + + scores = method(d1) + self.assertEqual(len(scores), 4) + + score = method(d1, c.petal_length) + self.assertIsInstance(score, float) + + def test_continuous_scores_on_discrete_features(self): + data = Impute()(self.imports) + with self.assertRaises(ValueError): + UnivariateLinearRegression()(data) + + d1 = SelectBestFeatures(method=UnivariateLinearRegression())(data) + self.assertEqual(len(d1.domain), len(data.domain)) + + def test_defaults(self): + fs = SelectBestFeatures(k=3) + data2 = fs(Impute()(self.imports)) + self.assertTrue(all(a.is_continuous for a in data2.domain.attributes)) + data2 = fs(self.iris) + self.assertTrue(all(a.is_continuous for a in data2.domain.attributes)) + data2 = fs(self.titanic) + self.assertTrue(all(a.is_discrete for a in data2.domain.attributes)) + + +class TestSelectRandomFeatures(unittest.TestCase): + def test_select_random_features(self): + data = Table("heart_disease") + for k_features, n_attributes in ((3, 3), (0.35, 4)): + srf = SelectRandomFeatures(k=k_features) + new_data = srf(data) + self.assertEqual(len(new_data.domain.attributes), n_attributes) diff --git a/pyminer2/tests/test_impute.py b/pyminer2/tests/test_impute.py new file mode 100644 index 0000000000000000000000000000000000000000..9be58f37abd31ba362e58588339dfa1287906d82 --- /dev/null +++ b/pyminer2/tests/test_impute.py @@ -0,0 +1,327 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from functools import reduce +import numpy as np +import scipy.sparse as sp + +from Orange import preprocess +from Orange.preprocess import impute +from Orange import data +from Orange.data import Unknown, Table + +from Orange.classification import MajorityLearner, SimpleTreeLearner +from Orange.regression import MeanLearner +from Orange.tests import test_filename + + +class TestReplaceUnknowns(unittest.TestCase): + def test_replacement(self): + a = np.arange(10, dtype=float) + a[1] = a[5] = Unknown + ia = preprocess.ReplaceUnknowns(None).transform(a) + np.testing.assert_equal(ia, [0, 0, 2, 3, 4, 0, 6, 7, 8, 9]) + + a[1] = a[5] = Unknown + ia = preprocess.ReplaceUnknowns(None, value=42).transform(a) + np.testing.assert_equal(ia, [0, 42, 2, 3, 4, 42, 6, 7, 8, 9]) + + def test_sparse(self): + m = sp.csr_matrix(np.eye(10)) + rm = preprocess.ReplaceUnknowns(None, value=42).transform(m) + self.assertEqual((m != rm).nnz, 0) + + def test_sparse_nans(self): + """ + Remove nans from sparse matrix. + GH-2295 + GH-2178 + """ + m = sp.csr_matrix(np.ones((3, 3))) + m[0, :] = np.nan + self.assertTrue(np.isnan(m.data).any()) + preprocess.ReplaceUnknowns(None, value=42.).transform(m) + self.assertFalse(np.isnan(m.data).any()) + + +class TestDropInstances(unittest.TestCase): + def test_drop(self): + X = np.random.rand(5, 3) + X[3:5, 1] = np.nan + table = data.Table.from_numpy(None, X) + drop = impute.DropInstances() + ind = drop(table, table.domain[1]) + self.assertEqual(list(ind), [False, False, False, True, True]) + + +class TestDoNotImpute(unittest.TestCase): + def test_str(self): + table = data.Table.from_file("iris") + imputer = impute.BaseImputeMethod() + var = table.domain[0] + self.assertIn(var.name, imputer.format_variable(var)) + self.assertIn(imputer.short_name, imputer.format_variable(var)) + self.assertIn(imputer.name, str(imputer)) + + def test_copy(self): + imputer = impute.BaseImputeMethod() + self.assertIs(imputer, imputer.copy()) + + def test_call(self): + X = np.random.rand(5, 3) + X[3:5, 1] = np.nan + table = data.Table.from_numpy(None, X) + imputer = impute.DoNotImpute() + var = imputer(table, table.domain[1]) + self.assertEqual(var, table.domain[1]) + + def test_support(self): + table = data.Table.from_file("iris") + continuous = table.domain.variables[0] + discrete = table.domain.variables[-1] + + imputer = impute.DoNotImpute() + self.assertTrue(imputer.supports_variable(discrete)) + self.assertTrue(imputer.supports_variable(continuous)) + + +class TestAverage(unittest.TestCase): + def test_replacement(self): + s = [0] * 50 + [1] * 50 + c1 = np.array(s).reshape((100, 1)) + s = [0] * 5 + [1] * 5 + [2] * 90 + c2 = np.array(s).reshape((100, 1)) + x = np.hstack([c1, c2]) + domain = data.Domain([data.ContinuousVariable("a"), + data.DiscreteVariable("b", values="ABC")], + data.ContinuousVariable("c"),) + table = Table(domain, x, c1) + for col, computed_value in ((0, 0.5), (1, 2)): + var1 = preprocess.Average()(table, col) + self.assertIsInstance(var1.compute_value, preprocess.ReplaceUnknowns) + self.assertEqual(var1.compute_value.value, computed_value) + + +class TestDefault(unittest.TestCase): + def test_replacement(self): + nan = np.nan + X = [ + [1.0, nan, 0.0], + [2.0, 1.0, 3.0], + [nan, nan, nan] + ] + + table = Table.from_numpy(None, np.array(X)) + var1 = impute.Default(0.0)(table, 0) + self.assertTrue(np.all(np.isfinite(var1.compute_value(table)))) + self.assertTrue(all(var1.compute_value(table) == [1.0, 2.0, 0.0])) + + imputer = preprocess.Impute(method=impute.Default(42)) + idata = imputer(table) + np.testing.assert_allclose( + idata.X, + [[1.0, 42., 0.0], + [2.0, 1.0, 3.0], + [42., 42., 42.]]) + + def test_default(self): + nan = np.nan + X = [[nan, 0.0], + [1.0, 3.0], + [nan, nan] + ] + domain = data.Domain( + (data.DiscreteVariable("B", values=["a", "b", "c"]), + data.ContinuousVariable("C")) + ) + table = data.Table.from_numpy(domain, np.array(X)) + + v2 = impute.Default(42)(table, domain["C"]) + self.assertEqual(v2.compute_value.value, 42) + + v3 = impute.Default()(table, domain["C"], default=42) + self.assertEqual(v3.compute_value.value, 42) + + def test_copy(self): + imputer = impute.Default(1) + copied = imputer.copy() + imputer.default = 2 + self.assertEqual(copied.default, 1) + + def test_str(self): + imputer = impute.Default(1) + self.assertIn('1', imputer.format_variable(data.Variable("y"))) + + +class TestAsValue(unittest.TestCase): + def _create_table(self): + nan = np.nan + X = [ + [1.0, nan, 0.0], + [2.0, 1.0, 3.0], + [nan, nan, nan] + ] + domain = data.Domain( + (data.DiscreteVariable("A", values=["0", "1", "2"]), + data.ContinuousVariable("B"), + data.ContinuousVariable("C")) + ) + return data.Table.from_numpy(domain, np.array(X)) + + def test_replacement(self): + table = self._create_table() + domain = table.domain + + v1 = impute.AsValue()(table, domain[0]) + self.assertTrue(np.all(np.isfinite(v1.compute_value(table)))) + self.assertTrue(np.all(v1.compute_value(table) == [1., 2., 3.])) + self.assertEqual([v1.str_val(v) for v in v1.compute_value(table)], + ["1", "2", "N/A"]) + + v1, v2 = impute.AsValue()(table, domain[1]) + self.assertTrue(np.all(np.isfinite(v1.compute_value(table)))) + self.assertTrue(np.all(np.isfinite(v2.compute_value(table)))) + self.assertTrue(np.all(v2.compute_value(table) == [0., 1., 0.])) + self.assertEqual([v2.str_val(v) for v in v2.compute_value(table)], + ["undef", "def", "undef"]) + + vars = reduce(lambda acc, v: + acc + (list(v) if isinstance(v, (tuple, list)) + else [v]), + [impute.AsValue()(table, var) for var in table.domain.variables], + []) + domain = data.Domain(vars) + idata = table.from_table(domain, table) + + np.testing.assert_allclose( + idata.X, + [[1, 1.0, 0, 0.0, 1], + [2, 1.0, 1, 3.0, 1], + [3, 1.0, 0, 1.5, 0]] + ) + + def test_sparse(self): + """ + Impute: As a distinct value test. Sparse support. + GH-2357 + """ + table = self._create_table() + domain = table.domain + table.X = sp.csr_matrix(table.X) + + v1, v2 = impute.AsValue()(table, domain[1]) + self.assertTrue(np.all(np.isfinite(v2.compute_value(table)))) + self.assertEqual([v2.str_val(v) for v in v2.compute_value(table)], + ["undef", "def", "undef"]) + + +class TestModel(unittest.TestCase): + def test_replacement(self): + nan = np.nan + X = [ + [1.0, nan, 0.0], + [2.0, 1.0, 3.0], + [nan, nan, nan] + ] + unknowns = np.isnan(X) + + domain = data.Domain( + (data.DiscreteVariable("A", values=["0", "1", "2"]), + data.ContinuousVariable("B"), + data.ContinuousVariable("C")) + ) + table = data.Table.from_numpy(domain, np.array(X)) + + v = impute.Model(MajorityLearner())(table, domain[0]) + self.assertTrue(np.all(np.isfinite(v.compute_value(table)))) + self.assertTrue(np.all(v.compute_value(table) == [1., 2., 1.]) or + np.all(v.compute_value(table) == [1., 2., 2.])) + v = impute.Model(MeanLearner())(table, domain[1]) + self.assertTrue(np.all(np.isfinite(v.compute_value(table)))) + self.assertTrue(np.all(v.compute_value(table) == [1., 1., 1.])) + + imputer = preprocess.Impute(impute.Model(SimpleTreeLearner())) + itable = imputer(table) + + # Original data should keep unknowns + self.assertTrue(np.all(np.isnan(table.X) == unknowns)) + self.assertTrue(np.all(itable.X[~unknowns] == table.X[~unknowns])) + + Aimp = itable.domain["A"].compute_value + self.assertIsInstance(Aimp, impute.ReplaceUnknownsModel) + + col = Aimp(table) + self.assertEqual(col.shape, (len(table),)) + self.assertTrue(np.all(np.isfinite(col))) + + v = Aimp(table[-1]) + self.assertEqual(v.shape, (1,)) + self.assertTrue(np.all(np.isfinite(v))) + + def test_copy(self): + imputer = impute.Model(MajorityLearner()) + copied = imputer.copy() + imputer.learner = MajorityLearner() + self.assertIsNot(copied.learner, imputer.learner) + + def test_support(self): + table = data.Table.from_file("iris") + continuous = table.domain.variables[0] + discrete = table.domain.variables[-1] + + imputer = impute.Model(MajorityLearner()) + self.assertTrue(imputer.supports_variable(discrete)) + self.assertFalse(imputer.supports_variable(continuous)) + + imputer = impute.Model(MeanLearner()) + self.assertFalse(imputer.supports_variable(discrete)) + self.assertTrue(imputer.supports_variable(continuous)) + + def test_str(self): + imputer = impute.Model(MajorityLearner()) + self.assertIn(MajorityLearner().name, + imputer.format_variable(data.Variable("y"))) + + def test_bad_domain(self): + table = data.Table.from_file('iris') + imputer = impute.Model(MajorityLearner()) + self.assertRaises(ValueError, imputer, data=table, + variable=table.domain[0]) + + +class TestRandom(unittest.TestCase): + def test_replacement(self): + nan = np.nan + X = [ + [1.0, nan, 0.0], + [2.0, 1.0, 3.0], + [nan, nan, nan] + ] + unknowns = np.isnan(X) + + domain = data.Domain( + (data.DiscreteVariable("A", values=["0", "1", "2"]), + data.ContinuousVariable("B"), + data.ContinuousVariable("C")) + ) + table = data.Table.from_numpy(domain, np.array(X)) + + for i in range(0, 3): + v = impute.Random()(table, domain[i]) + self.assertTrue(np.all(np.isfinite(v.compute_value(table)))) + + imputer = preprocess.Impute(method=impute.Random()) + itable = imputer(table) + self.assertTrue(np.all(np.isfinite(itable.X))) + + # Original data should keep unknowns + self.assertTrue(np.all(unknowns == np.isnan(table.X))) + self.assertTrue(np.all(itable.X[~unknowns] == table.X[~unknowns])) + + +class TestImputer(unittest.TestCase): + def test_imputer(self): + auto = data.Table(test_filename('datasets/imports-85.tab')) + auto2 = preprocess.Impute()(auto) + self.assertFalse(np.isnan(auto2.X).any()) diff --git a/pyminer2/tests/test_instance.py b/pyminer2/tests/test_instance.py new file mode 100644 index 0000000000000000000000000000000000000000..6646e55e9970b01d0c67a2caf7a55426bdbbbbf7 --- /dev/null +++ b/pyminer2/tests/test_instance.py @@ -0,0 +1,315 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +from math import isnan +import unittest +from unittest.mock import MagicMock + +import numpy as np +from numpy.testing import assert_array_equal + +from Orange.data import \ + Instance, Domain, Unknown, Value, \ + DiscreteVariable, ContinuousVariable, StringVariable +from Orange.tests import assert_array_nanequal + + +class TestInstance(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.attributes = ["Feature %i" % i for i in range(10)] + cls.class_vars = ["Class %i" % i for i in range(1)] + cls.metas = [DiscreteVariable("Meta 1", values="XYZ"), + ContinuousVariable("Meta 2"), + StringVariable("Meta 3")] + + def mock_domain(self, with_classes=False, with_metas=False): + class_vars = self.class_vars if with_classes else [] + metas = self.metas if with_metas else [] + variables = self.attributes + class_vars + return MagicMock(Domain, + attributes=self.attributes, + class_vars=class_vars, + metas=metas, + variables=variables) + + def create_domain(self, attributes=(), classes=(), metas=()): + attr_vars = [ContinuousVariable(name=a) if isinstance(a, str) else a + for a in attributes] + class_vars = [ContinuousVariable(name=c) if isinstance(c, str) else c + for c in classes] + meta_vars = [DiscreteVariable(name=m, values=map(str, range(5))) + if isinstance(m, str) else m + for m in metas] + domain = Domain(attr_vars, class_vars, meta_vars) + return domain + + def test_init_x_no_data(self): + domain = self.mock_domain() + inst = Instance(domain) + self.assertIsInstance(inst, Instance) + self.assertIs(inst.domain, domain) + self.assertEqual(inst._x.shape, (len(self.attributes), )) + self.assertEqual(inst._y.shape, (0, )) + self.assertEqual(inst._metas.shape, (0, )) + self.assertTrue(all(isnan(x) for x in inst._x)) + + def test_init_xy_no_data(self): + domain = self.mock_domain(with_classes=True) + inst = Instance(domain) + self.assertIsInstance(inst, Instance) + self.assertIs(inst.domain, domain) + self.assertEqual(inst._x.shape, (len(self.attributes), )) + self.assertEqual(inst._y.shape, (len(self.class_vars), )) + self.assertEqual(inst._metas.shape, (0, )) + self.assertTrue(all(isnan(x) for x in inst._x)) + self.assertTrue(all(isnan(x) for x in inst._y)) + + def test_init_xym_no_data(self): + domain = self.mock_domain(with_classes=True, with_metas=True) + inst = Instance(domain) + self.assertIsInstance(inst, Instance) + self.assertIs(inst.domain, domain) + self.assertEqual(inst._x.shape, (len(self.attributes), )) + self.assertEqual(inst._y.shape, (len(self.class_vars), )) + self.assertEqual(inst._metas.shape, (3, )) + self.assertTrue(all(isnan(x) for x in inst._x)) + self.assertTrue(all(isnan(x) for x in inst._y)) + + assert_array_nanequal(inst._metas, + np.array([var.Unknown for var in domain.metas], + dtype=object)) + + def test_init_x_arr(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")]) + vals = np.array([42, 0]) + inst = Instance(domain, vals) + assert_array_equal(inst._x, vals) + self.assertEqual(inst._y.shape, (0, )) + self.assertEqual(inst._metas.shape, (0, )) + + domain = self.create_domain() + inst = Instance(domain, np.empty((0,))) + self.assertEqual(inst._x.shape, (0, )) + self.assertEqual(inst._y.shape, (0, )) + self.assertEqual(inst._metas.shape, (0, )) + + def test_init_x_list(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")]) + lst = [42, 0] + vals = np.array(lst) + inst = Instance(domain, vals) + assert_array_equal(inst._x, vals) + self.assertEqual(inst._y.shape, (0, )) + self.assertEqual(inst._metas.shape, (0, )) + + domain = self.create_domain() + inst = Instance(domain, []) + self.assertEqual(inst._x.shape, (0, )) + self.assertEqual(inst._y.shape, (0, )) + self.assertEqual(inst._metas.shape, (0, )) + + def test_init_xy_arr(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")]) + vals = np.array([42, 0, 1]) + inst = Instance(domain, vals) + assert_array_equal(inst._x, vals[:2]) + self.assertEqual(inst._y.shape, (1, )) + self.assertEqual(inst._y[0], 1) + self.assertEqual(inst._metas.shape, (0, )) + + def test_init_xy_list(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")]) + vals = np.array([42, 0, 2]) + inst = Instance(domain, vals) + assert_array_equal(inst._x, vals[:2]) + self.assertEqual(inst._y.shape, (1, )) + self.assertEqual(inst._y[0], 2) + self.assertEqual(inst._metas.shape, (0, )) + + def test_init_xym(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + for val in (np.array([42, "M", "B", "X", 43, "Foo"], dtype=object), + [42, "M", "B", "X", 43, "Foo"]): + inst = Instance(domain, val) + self.assertIsInstance(inst, Instance) + self.assertIs(inst.domain, domain) + self.assertEqual(inst._x.shape, (2,)) + self.assertEqual(inst._y.shape, (1,)) + self.assertEqual(inst._metas.shape, (3,)) + assert_array_equal(inst._x, np.array([42, 0])) + self.assertEqual(inst._y[0], 1) + assert_array_equal(inst._metas, np.array([0, 43, "Foo"], dtype=object)) + + def test_init_inst(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + vals = [42, "M", "B", "X", 43, "Foo"] + inst = Instance(domain, vals) + + inst2 = Instance(domain, inst) + assert_array_equal(inst2._x, np.array([42, 0])) + self.assertEqual(inst2._y[0], 1) + assert_array_equal(inst2._metas, np.array([0, 43, "Foo"], dtype=object)) + + domain2 = self.create_domain(["z", domain[1], self.metas[1]], + domain.class_vars, + [self.metas[0], "w", domain[0]]) + inst2 = Instance(domain2, inst) + + assert_array_nanequal(inst2._x, np.array([Unknown, 0, 43])) + self.assertEqual(inst2._y[0], 1) + assert_array_nanequal(inst2._metas, np.array([0, Unknown, 42], + dtype=object)) + + def test_get_item(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + vals = [42, "M", "B", "X", 43, "Foo"] + inst = Instance(domain, vals) + for idx_int, idx_name, idx_var, value in ((0, "x", domain[0], 42), + (1, "g", domain[1], "M"), + (2, "y", domain.class_var, "B"), + (-2, "Meta 2", self.metas[1], 43)): + val = inst[idx_int] + self.assertIsInstance(val, Value) + self.assertEqual(inst[idx_int], value) + self.assertEqual(inst[idx_name], value) + self.assertEqual(inst[idx_var], value) + + with self.assertRaises(ValueError): + inst["asdf"] = 42 + with self.assertRaises(ValueError): + inst[ContinuousVariable("asdf")] = 42 + + def test_list(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + vals = [42, "M", "B", "X", 43, "Foo"] + inst = Instance(domain, vals) + + l = inst.list + self.assertIsInstance(l, list) + self.assertEqual(l, [42, "M", "B", "X", 43, "Foo"]) + self.assertGreater(len(l), len(inst)) + self.assertEqual(len(l), 6) + + def test_set_item(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + vals = [42, "M", "B", "X", 43, "Foo"] + inst = Instance(domain, vals) + + for idx1, idx2, val in ((0, 0, 42), + ("x", 0, 44), + (1, 1, "F"), + ("g", 1, "M"), + (2, 2, "C"), + ("y", 2, "A"), + (domain.class_var, 2, "B"), + (-1, -1, "Y"), + ("Meta 1", -1, "Z"), + (domain.metas[0], -1, "X")): + inst[idx1] = val + self.assertEqual(inst[idx2], val) + + with self.assertRaises(ValueError): + inst[1] = "N" + with self.assertRaises(ValueError): + inst["asdf"] = 42 + + def test_str(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")]) + inst = Instance(domain, [42, 0]) + self.assertEqual(str(inst), "[42, M]") + + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")]) + inst = Instance(domain, [42, "M", "B"]) + self.assertEqual(str(inst), "[42, M | B]") + + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + inst = Instance(domain, [42, "M", "B", "X", 43, "Foo"]) + self.assertEqual(str(inst), "[42, M | B] {X, 43, Foo}") + + domain = self.create_domain([], + [DiscreteVariable("y", values="ABC")], + self.metas) + inst = Instance(domain, ["B", "X", 43, "Foo"]) + self.assertEqual(str(inst), "[ | B] {X, 43, Foo}") + + domain = self.create_domain([], + [], + self.metas) + inst = Instance(domain, ["X", 43, "Foo"]) + self.assertEqual(str(inst), "[] {X, 43, Foo}") + + domain = self.create_domain(self.attributes) + inst = Instance(domain, range(len(self.attributes))) + self.assertEqual( + str(inst), + "[{}]".format(", ".join(f"{x:g}" + for x in range(len(self.attributes))))) + + for attr in domain.variables: + attr.number_of_decimals = 0 + self.assertEqual( + str(inst), + "[{}]".format(", ".join("{}".format(x) + for x in range(len(self.attributes))))) + + def test_repr(self): + domain = self.create_domain(self.attributes) + inst = Instance(domain, range(len(self.attributes))) + self.assertEqual(repr(inst), "[0, 1, 2, 3, 4, ...]") + + for attr in domain.variables: + attr.number_of_decimals = 3 + self.assertEqual(repr(inst), "[0.000, 1.000, 2.000, 3.000, 4.000, ...]") + + for attr in domain.variables: + attr.number_of_decimals = 0 + self.assertEqual(repr(inst), "[0, 1, 2, 3, 4, ...]") + + def test_eq(self): + domain = self.create_domain(["x", DiscreteVariable("g", values="MF")], + [DiscreteVariable("y", values="ABC")], + self.metas) + vals = [42, "M", "B", "X", 43, "Foo"] + inst = Instance(domain, vals) + inst2 = Instance(domain, vals) + self.assertEqual(inst, inst2) + self.assertEqual(inst2, inst) + + inst2[0] = 43 + self.assertNotEqual(inst, inst2) + + inst2[0] = Unknown + self.assertNotEqual(inst, inst2) + + for index, val in ((2, "C"), (-1, "Y"), (-2, "33"), (-3, "Bar")): + inst2 = Instance(domain, vals) + inst2[index] = val + self.assertNotEqual(inst, inst2) + + def test_instance_id(self): + domain = self.create_domain(["x"]) + vals = [42] + + inst = Instance(domain, vals, id=42) + self.assertEqual(inst.id, 42) + + inst2 = Instance(domain, vals) + inst3 = Instance(domain, vals) + + self.assertNotEqual(inst2.id, inst3.id) diff --git a/pyminer2/tests/test_io.py b/pyminer2/tests/test_io.py new file mode 100644 index 0000000000000000000000000000000000000000..9a1985579998e8b7d7fb5603fb26aaf4c7bc439b --- /dev/null +++ b/pyminer2/tests/test_io.py @@ -0,0 +1,182 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import Mock, patch +import os +import tempfile +import shutil +import io + +from Orange import data + +from Orange.data.io import FileFormat, TabReader, CSVReader, PickleReader +from Orange.data.table import get_sample_datasets_dir +from Orange.data import Table, Variable +from Orange.tests import test_dirname + + +class WildcardReader(FileFormat): + EXTENSIONS = ('.wild', '.wild[0-9]') + DESCRIPTION = "Dummy reader for testing extensions" + + def read(self): + pass + + +class TestChooseReader(unittest.TestCase): + + def test_usual_extensions(self): + self.assertIsInstance(FileFormat.get_reader("t.tab"), TabReader) + self.assertIsInstance(FileFormat.get_reader("t.csv"), CSVReader) + self.assertIsInstance(FileFormat.get_reader("t.pkl"), PickleReader) + with self.assertRaises(OSError): + FileFormat.get_reader("test.undefined_extension") + + def test_wildcard_extension(self): + self.assertIsInstance(FileFormat.get_reader("t.wild"), + WildcardReader) + self.assertIsInstance(FileFormat.get_reader("t.wild2"), + WildcardReader) + with self.assertRaises(OSError): + FileFormat.get_reader("t.wild2a") + + +class SameExtension(FileFormat): + PRIORITY = 100 + EXTENSIONS = ('.same_extension',) + DESCRIPTION = "Same extension, different priority" + + def read(self): + pass + + +class SameExtensionPreferred(SameExtension): + PRIORITY = 90 + + +class SameExtensionL(SameExtension): + PRIORITY = 110 + + +class TestMultipleSameExtension(unittest.TestCase): + + def test_find_reader(self): + reader = FileFormat.get_reader("some.same_extension") + self.assertIsInstance(reader, SameExtensionPreferred) + + +class TestLocate(unittest.TestCase): + + def test_locate_sample_datasets(self): + with self.assertRaises(OSError): + FileFormat.locate("iris.tab", + search_dirs=[os.path.dirname(__file__)]) + iris = FileFormat.locate("iris.tab", + search_dirs=[get_sample_datasets_dir()]) + self.assertEqual(os.path.basename(iris), "iris.tab") + # test extension adding + iris = FileFormat.locate("iris", + search_dirs=[get_sample_datasets_dir()]) + self.assertEqual(os.path.basename(iris), "iris.tab") + + def test_locate_wildcard_extension(self): + tempdir = tempfile.mkdtemp() + with self.assertRaises(OSError): + FileFormat.locate("t.wild9", search_dirs=[tempdir]) + fn = os.path.join(tempdir, "t.wild8") + with open(fn, "wt") as f: + f.write("\n") + location = FileFormat.locate("t.wild8", search_dirs=[tempdir]) + self.assertEqual(location, fn) + # test extension adding + location = FileFormat.locate("t", search_dirs=[tempdir]) + self.assertEqual(location, fn) + shutil.rmtree(tempdir) + + +class TestReader(unittest.TestCase): + + def setUp(self): + data.table.dataset_dirs.append(test_dirname()) + + def tearDown(self): + data.table.dataset_dirs.remove(test_dirname()) + + def test_open_bad_pickle(self): + """ + Raise TypeError when PickleReader reads a pickle + file without a table (and it suppose to be there). + GH-2232 + """ + reader = PickleReader("") + with unittest.mock.patch("pickle.load", return_value=None): + self.assertRaises(TypeError, reader.read, "foo") + + def test_empty_columns(self): + """Can't read files with more columns then headers. GH-1417""" + samplefile = """\ + a, b + 1, 0, + 1, 2, + """ + c = io.StringIO(samplefile) + with self.assertWarns(UserWarning) as cm: + table = CSVReader(c).read() + self.assertEqual(len(table.domain.attributes), 2) + self.assertEqual(cm.warning.args[0], + "Columns with no headers were removed.") + + def test_type_annotations(self): + class FooFormat(FileFormat): + write_file = Mock() + + FooFormat.write('test_file', None) + FooFormat.write_file.assert_called_with('test_file', None) + + FooFormat.OPTIONAL_TYPE_ANNOTATIONS = True + FooFormat.write('test_file', None) + FooFormat.write_file.assert_called_with('test_file', None, True) + + FooFormat.write('test_file', None, False) + FooFormat.write_file.assert_called_with('test_file', None, False) + + FooFormat.OPTIONAL_TYPE_ANNOTATIONS = False + FooFormat.write('test_file', None) + FooFormat.write_file.assert_called_with('test_file', None) + + @patch('csv.DictWriter.writerow') + def test_header_call(self, writer): + CSVReader.write_headers(writer, Table("iris"), False) + self.assertEqual(len(writer.call_args_list), 1) + + writer.reset_mock() + CSVReader.write_headers(writer, Table("iris"), True) + self.assertEqual(len(writer.call_args_list), 3) + + def test_load_pickle(self): + """ + This function tests whether pickled files in older Orange loads + correctly with newer version of Orange. + """ + # load pickles created with Orange 3.20 + # in next version there is a change in variables.py - line 738 + # which broke back compatibility - tests were introduced after the fix + data1 = Table("datasets/sailing-orange-3-20.pkl") + data2 = Table("datasets/sailing-orange-3-20.pkl.gz") + + # load pickles created with Orange 3.21 + data3 = Table("datasets/sailing-orange-3-21.pkl") + data4 = Table("datasets/sailing-orange-3-21.pkl.gz") + + examples_count = 20 + self.assertEqual(examples_count, len(data1)) + self.assertEqual(examples_count, len(data2)) + self.assertEqual(examples_count, len(data3)) + self.assertEqual(examples_count, len(data4)) + + attributes_count = 3 + self.assertEqual(attributes_count, len(data1.domain.attributes)) + self.assertEqual(attributes_count, len(data2.domain.attributes)) + self.assertEqual(attributes_count, len(data3.domain.attributes)) + self.assertEqual(attributes_count, len(data4.domain.attributes)) diff --git a/pyminer2/tests/test_knn.py b/pyminer2/tests/test_knn.py new file mode 100644 index 0000000000000000000000000000000000000000..fa02106605f29f0071eef9e4a8a3467377adf6da --- /dev/null +++ b/pyminer2/tests/test_knn.py @@ -0,0 +1,69 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np + +from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable +from Orange.classification import KNNLearner +from Orange.regression import KNNRegressionLearner +from Orange.evaluation import CA, CrossValidation, MSE + + +class TestKNNLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.housing = Table('housing') + + def test_KNN(self): + cv = CrossValidation(k=3) + results = cv(self.iris, [KNNLearner()]) + ca = CA(results) + self.assertGreater(ca, 0.8) + self.assertLess(ca, 0.99) + + def test_predict_single_instance(self): + lrn = KNNLearner() + clf = lrn(self.iris) + for ins in self.iris[::20]: + clf(ins) + val, prob = clf(ins, clf.ValueProbs) + + def test_random(self): + nrows, ncols = 1000, 5 + x = np.random.randint(-20, 51, (nrows, ncols)) + y = np.random.randint(0, 9, (nrows, 1)) + x1, x2 = np.split(x, 2) + y1, y2 = np.split(y, 2) + attr = (ContinuousVariable('Feature 1'), + ContinuousVariable('Feature 2'), + ContinuousVariable('Feature 3'), + ContinuousVariable('Feature 4'), + ContinuousVariable('Feature 5')) + class_vars = (DiscreteVariable('Target 1', values=list("abcdefghij")),) + domain = Domain(attr, class_vars) + t = Table(domain, x1, y1) + lrn = KNNLearner() + clf = lrn(t) + z = clf(x2) + correct = (z == y2.flatten()) + ca = sum(correct) / len(correct) + self.assertGreater(ca, 0.1) + self.assertLess(ca, 0.3) + + def test_KNN_mahalanobis(self): + learners = [KNNLearner(metric="mahalanobis")] + cv = CrossValidation(k=3) + results = cv(self.iris, learners) + ca = CA(results) + self.assertGreater(ca, 0.8) + + def test_KNN_regression(self): + learners = [KNNRegressionLearner(), + KNNRegressionLearner(metric="mahalanobis")] + cv = CrossValidation(k=3) + results = cv(self.housing, learners) + mse = MSE(results) + self.assertLess(mse[1], mse[0]) diff --git a/pyminer2/tests/test_lda.py b/pyminer2/tests/test_lda.py new file mode 100644 index 0000000000000000000000000000000000000000..bf61672bad996c544a852f7f89923eb760ce766e --- /dev/null +++ b/pyminer2/tests/test_lda.py @@ -0,0 +1,49 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np + +from Orange.preprocess import Continuize, Randomize +from Orange.projection import LDA +from Orange.data import Table + + +class TestLDA(unittest.TestCase): + def test_lda(self): + iris = Table('iris') + n_components = 2 + lda = LDA(solver="eigen", n_components=n_components) + model = lda(iris) + transformed = model(iris) + self.assertEqual(transformed.X.shape, (len(iris), n_components)) + self.assertEqual(transformed.Y.shape, (len(iris),)) + + def test_transform_changed_domain(self): + """ + 1. Open data, apply some preprocessor, splits the data into two parts, + use LDA on the first part, and then transform the second part. + + 2. Open data, split into two parts, apply the same preprocessor and + LDA only on the first part, and then transform the second part. + + The transformed second part in (1) and (2) has to be the same. + """ + data = Table("iris") + data = Randomize()(data) + preprocessor = Continuize() + lda = LDA() + + # normalize all + ndata = preprocessor(data) + + model = lda(ndata[:75]) + result_1 = model(ndata[75:]) + + # normalize only the "training" part + ndata = preprocessor(data[:75]) + model = lda(ndata) + result_2 = model(data[75:]) + + np.testing.assert_almost_equal(result_1.X, result_2.X) diff --git a/pyminer2/tests/test_linear_bfgs_regression.py b/pyminer2/tests/test_linear_bfgs_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..b4abd5053f7e2bffd82d5db87e6f3ee091f3f858 --- /dev/null +++ b/pyminer2/tests/test_linear_bfgs_regression.py @@ -0,0 +1,19 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table +from Orange.evaluation import CrossValidation, RMSE +from Orange.regression.linear_bfgs import LinearRegressionLearner + + +class TestLinearRegressionLearner(unittest.TestCase): + def test_preprocessors(self): + table = Table('housing') + learners = [LinearRegressionLearner(preprocessors=[]), + LinearRegressionLearner()] + cv = CrossValidation(k=3) + results = cv(table, learners) + rmse = RMSE(results) + self.assertLess(rmse[0], rmse[1]) diff --git a/pyminer2/tests/test_linear_regression.py b/pyminer2/tests/test_linear_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..97c28b23fae2fb6d42cc22d734071dc16958daf6 --- /dev/null +++ b/pyminer2/tests/test_linear_regression.py @@ -0,0 +1,120 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +from sklearn import linear_model + +from Orange.data import Table +from Orange.regression import (LinearRegressionLearner, + RidgeRegressionLearner, + LassoRegressionLearner, + ElasticNetLearner, + ElasticNetCVLearner, + MeanLearner) +from Orange.evaluation import CrossValidation, RMSE + + +class TestLinearRegressionLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.housing = Table("housing") + + def test_LinearRegression(self): + nrows = 1000 + ncols = 3 + x = np.random.randint(-20, 51, (nrows, ncols)) + c = np.random.rand(ncols, 1) * 10 - 3 + e = np.random.rand(nrows, 1) - 0.5 + y = np.dot(x, c) + e + + x1, x2 = np.split(x, 2) + y1, y2 = np.split(y, 2) + t = Table.from_numpy(None, x1, y1) + learn = LinearRegressionLearner() + clf = learn(t) + z = clf(x2) + self.assertTrue((abs(z.reshape(-1, 1) - y2) < 2.0).all()) + + def test_Regression(self): + ridge = RidgeRegressionLearner() + lasso = LassoRegressionLearner() + elastic = ElasticNetLearner() + elasticCV = ElasticNetCVLearner() + mean = MeanLearner() + learners = [ridge, lasso, elastic, elasticCV, mean] + cv = CrossValidation(k=2) + res = cv(self.housing, learners) + rmse = RMSE(res) + for i in range(len(learners) - 1): + self.assertLess(rmse[i], rmse[-1]) + + def test_linear_scorer(self): + learner = LinearRegressionLearner() + scores = learner.score_data(self.housing) + self.assertEqual( + 'LSTAT', self.housing.domain.attributes[np.argmax(scores[0])].name) + self.assertEqual(scores.shape[1], len(self.housing.domain.attributes)) + + def test_scorer(self): + learners = [LinearRegressionLearner(), + RidgeRegressionLearner(), + LassoRegressionLearner(alpha=0.01), + ElasticNetLearner(alpha=0.01)] + for learner in learners: + scores = learner.score_data(self.housing) + self.assertEqual( + 'LSTAT', + self.housing.domain.attributes[np.argmax(scores[0])].name) + self.assertEqual(scores.shape[1], + len(self.housing.domain.attributes)) + + def test_scorer_feature(self): + learners = [LinearRegressionLearner(), + RidgeRegressionLearner(), + LassoRegressionLearner(alpha=0.01), + ElasticNetLearner(alpha=0.01)] + for learner in learners: + scores = learner.score_data(self.housing) + for i, attr in enumerate(self.housing.domain.attributes): + score = learner.score_data(self.housing, attr) + np.testing.assert_array_almost_equal(score, scores[:, i]) + + def test_coefficients(self): + data = Table.from_numpy(None, [[11], [12], [13]], [0, 1, 2]) + model = LinearRegressionLearner()(data) + self.assertAlmostEqual(float(model.intercept), -11) + self.assertEqual(len(model.coefficients), 1) + self.assertAlmostEqual(float(model.coefficients[0]), 1) + + def test_comparison_with_sklearn(self): + alphas = [0.001, 0.1, 1, 10, 100] + learners = [(LassoRegressionLearner, linear_model.Lasso), + (RidgeRegressionLearner, linear_model.Ridge), + (ElasticNetLearner, linear_model.ElasticNet)] + for o_learner, s_learner in learners: + for a in alphas: + lr = o_learner(alpha=a) + o_model = lr(self.housing) + s_model = s_learner(alpha=a, fit_intercept=True) + s_model.fit(self.housing.X, self.housing.Y) + delta = np.sum(s_model.coef_ - o_model.coefficients) + self.assertAlmostEqual(delta, 0.0) + + def test_comparison_elastic_net(self): + alphas = [0.001, 0.1, 1, 10, 100] + for a in alphas: + lasso = LassoRegressionLearner(alpha=a) + lasso_model = lasso(self.housing) + en = ElasticNetLearner(alpha=a, l1_ratio=1) + en_model = en(self.housing) + np.testing.assert_allclose( + lasso_model.coefficients, en_model.coefficients, atol=1e-07) + + def test_linear_regression_repr(self): + learner = LinearRegressionLearner() + repr_text = repr(learner) + learner2 = eval(repr_text) + + self.assertIsInstance(learner2, LinearRegressionLearner) diff --git a/pyminer2/tests/test_logistic_regression.py b/pyminer2/tests/test_logistic_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..2b9df4ce5199e2a55643083b92503e81e9356cc5 --- /dev/null +++ b/pyminer2/tests/test_logistic_regression.py @@ -0,0 +1,136 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +import sklearn + +from Orange.data import Table, ContinuousVariable, Domain +from Orange.classification import LogisticRegressionLearner, Model +from Orange.evaluation import CrossValidation, CA + + +class TestLogisticRegressionLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.heart_disease = Table('heart_disease.tab') + cls.zoo = Table('zoo') + + def test_LogisticRegression(self): + learn = LogisticRegressionLearner() + cv = CrossValidation(k=2) + results = cv(self.heart_disease, [learn]) + ca = CA(results) + self.assertGreater(ca, 0.8) + self.assertLess(ca, 1.0) + + @unittest.skip("Re-enable when Logistic regression supports normalization.") + def test_LogisticRegressionNormalization(self): + np.random.seed(42) + new_attrs = (ContinuousVariable('c0'),) + self.iris.domain.attributes + new_domain = Domain(new_attrs, + self.iris.domain.class_vars, + self.iris.domain.metas) + new_table = np.hstack(( + 1000000 * np.random.random((self.iris.X.shape[0], 1)), + self.iris)) + table = self.iris.from_numpy(new_domain, new_table) + lr = LogisticRegressionLearner(normalize=False) + lr_norm = LogisticRegressionLearner(normalize=True) + + # check that normalization produces better results + cv = CrossValidation(k=3) + results = cv(table, [lr_norm, lr]) + ca = CA(results) + self.assertGreater(ca[0], ca[1]) + + # check that coefficients are properly scaled back to unnormalized data + model = lr_norm(table) + y = np.argmax(np.dot(table.X, model.coefficients.T) + model.intercept, + axis=1) + np.testing.assert_array_equal(model(table), y) + + def test_LogisticRegressionNormalization_todo(self): + with self.assertRaises(TypeError): + lr = LogisticRegressionLearner(normalize=True) + # Do not skip the above test when this is implemented + + def test_probability(self): + learn = LogisticRegressionLearner(penalty='l1') + clf = learn(self.iris[:100]) + p = clf(self.iris[100:], ret=Model.Probs) + self.assertLess(abs(p.sum(axis=1) - 1).all(), 1e-6) + + def test_learner_scorer(self): + learner = LogisticRegressionLearner() + scores = learner.score_data(self.heart_disease) + self.assertEqual('major vessels colored', + self.heart_disease.domain.attributes[np.argmax(scores)].name) + self.assertEqual(scores.shape, (1, len(self.heart_disease.domain.attributes))) + + def test_learner_scorer_feature(self): + learner = LogisticRegressionLearner() + scores = learner.score_data(self.heart_disease) + for i, attr in enumerate(self.heart_disease.domain.attributes): + score = learner.score_data(self.heart_disease, attr) + np.testing.assert_array_almost_equal(score, scores[:, i]) + + def test_learner_scorer_previous_transformation(self): + learner = LogisticRegressionLearner() + from Orange.preprocess import Discretize + data = Discretize()(self.iris) + scores = learner.score_data(data) + # scores should be defined and positive + self.assertTrue(np.all(scores > 0)) + + def test_learner_scorer_multiclass(self): + attr = self.zoo.domain.attributes + learner = LogisticRegressionLearner() + scores = learner.score_data(self.zoo) + self.assertEqual('aquatic', attr[np.argmax(scores[0])].name) # amphibian + self.assertEqual('feathers', attr[np.argmax(scores[1])].name) # bird + self.assertEqual('fins', attr[np.argmax(scores[2])].name) # fish + self.assertEqual('legs', attr[np.argmax(scores[3])].name) # insect + self.assertEqual('backbone', attr[np.argmax(scores[4])].name) # invertebrate + self.assertEqual('milk', attr[np.argmax(scores[5])].name) # mammal + self.assertEqual('hair', attr[np.argmax(scores[6])].name) # reptile + self.assertEqual(scores.shape, + (len(self.zoo.domain.class_var.values), len(attr))) + + def test_learner_scorer_multiclass_feature(self): + learner = LogisticRegressionLearner() + scores = learner.score_data(self.zoo) + for i, attr in enumerate(self.zoo.domain.attributes): + score = learner.score_data(self.zoo, attr) + np.testing.assert_array_almost_equal(score, scores[:, i]) + + def test_coefficients(self): + learn = LogisticRegressionLearner() + model = learn(self.heart_disease) + coef = model.coefficients + self.assertEqual(len(coef[0]), len(model.domain.attributes)) + + def test_predict_on_instance(self): + lr = LogisticRegressionLearner() + m = lr(self.zoo) + probs = m(self.zoo[50], m.Probs) + probs2 = m(self.zoo[50, :], m.Probs) + np.testing.assert_almost_equal(probs, probs2[0]) + + def test_single_class(self): + t = self.iris[60:90] + self.assertEqual(len(np.unique(t.Y)), 1) + learn = LogisticRegressionLearner() + with self.assertWarns(UserWarning): + model = learn(t) + self.assertEqual(model(t[0]), 1) + self.assertTrue(np.all(model(t[0], ret=Model.Probs) == [0, 1, 0])) + self.assertTrue(np.all(model(t) == 1)) + + def test_sklearn_single_class(self): + t = self.iris[60:90] + self.assertEqual(len(np.unique(t.Y)), 1) + lr = sklearn.linear_model.LogisticRegression() + self.assertRaises(ValueError, lr.fit, t.X, t.Y) diff --git a/pyminer2/tests/test_majority.py b/pyminer2/tests/test_majority.py new file mode 100644 index 0000000000000000000000000000000000000000..4b41acff84c0c0595c55da0799353efc39319be1 --- /dev/null +++ b/pyminer2/tests/test_majority.py @@ -0,0 +1,85 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np + +from Orange.data import Table +from Orange.classification import MajorityLearner +from Orange.tests import test_filename + + +class TestMajorityLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.learn = MajorityLearner() + + def test_majority(self): + nrows = 1000 + ncols = 10 + x = np.random.randint(1, 4, (nrows, ncols)) + y = np.random.randint(1, 4, (nrows, 1)) // 2 + t = Table.from_numpy(None, x, y) + clf = self.learn(t) + + x2 = np.random.randint(1, 4, (nrows, ncols)) + y2 = clf(x2) + self.assertEqual(y2.all(), 1) + + def test_weights(self): + nrows = 100 + ncols = 10 + x = np.random.randint(1, 5, (nrows, ncols)) + y = np.array(70*[0] + 30*[1]).reshape((nrows, 1)) + heavy_class = 1 + w = (y == heavy_class) * 2 + 1 + t = Table.from_numpy(None, x, y, W=w) + clf = self.learn(t) + + y2 = clf(x) + self.assertEqual(y2.all(), heavy_class) + + def test_empty(self): + clf = self.learn(self.iris[:0]) + y = clf(self.iris[0], clf.Probs) + self.assertTrue(np.allclose(y, y.sum() / y.size)) + + def test_missing(self): + iris = Table('iris') + learn = MajorityLearner() + for e in iris[: len(iris) // 2: 2]: + e.set_class("?") + clf = learn(iris) + y = clf(iris) + self.assertTrue((y == 2).all()) + + for e in iris: + e.set_class("?") + clf = learn(iris) + y = clf(iris) + self.assertEqual(y.all(), 1) + + def test_continuous(self): + autompg = Table(test_filename('datasets/imports-85.tab')) + learn = MajorityLearner() + self.assertRaises(ValueError, learn, autompg) + + def test_returns_random_class(self): + iris = self.iris + train = np.ones((150,), dtype='bool') + train[0] = False + majority = MajorityLearner()(iris[train]) + pred1 = majority(iris[0]) + self.assertIn(pred1, [1, 2]) + + for i in range(1, 50): + train[i] = train[50 + i] = train[100 + i] = False + majority = MajorityLearner()(iris[train]) + pred2 = majority(iris[0]) + self.assertIn(pred2, [1, 2]) + if pred1 != pred2: + break + else: + self.fail("Majority always returns the same value.") diff --git a/pyminer2/tests/test_manifold.py b/pyminer2/tests/test_manifold.py new file mode 100644 index 0000000000000000000000000000000000000000..cf332ea22d68d99213b06510caa4170d252b4121 --- /dev/null +++ b/pyminer2/tests/test_manifold.py @@ -0,0 +1,247 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +from sklearn.metrics import accuracy_score +from sklearn.neighbors import KNeighborsClassifier + +from Orange.data import Table +from Orange.distance import Euclidean +from Orange.projection import (MDS, Isomap, LocallyLinearEmbedding, + SpectralEmbedding, TSNE) +from Orange.projection.manifold import torgerson +from Orange.tests import test_filename + + +np.random.seed(42) + + +class TestManifold(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.ionosphere = Table(test_filename('datasets/ionosphere.tab')) + cls.iris = Table('iris') + + def test_mds(self): + data = self.ionosphere[:50] + for i in range(1, 4): + self.__mds_test_helper(data, n_com=i) + + def __mds_test_helper(self, data, n_com): + mds_fit = MDS( + n_components=n_com, dissimilarity=Euclidean, random_state=0) + mds_fit = mds_fit(data) + + mds_odist = MDS( + n_components=n_com, dissimilarity='precomputed', random_state=0) + mds_odist = mds_odist(Euclidean(data)) + + mds_sdist = MDS( + n_components=n_com, dissimilarity='euclidean', random_state=0) + mds_sdist = mds_sdist(data) + + eshape = data.X.shape[0], n_com + self.assertTrue(np.allclose(mds_fit.embedding_, mds_odist.embedding_)) + self.assertTrue(np.allclose(mds_fit.embedding_, mds_sdist.embedding_)) + self.assertEqual(eshape, mds_fit.embedding_.shape) + self.assertEqual(eshape, mds_odist.embedding_.shape) + self.assertEqual(eshape, mds_sdist.embedding_.shape) + + def test_mds_pca_init(self): + result = np.array([-2.6928912, 0.32603512]) + + projector = MDS( + n_components=2, dissimilarity=Euclidean, init_type='PCA', + n_init=1) + X = projector(self.iris).embedding_ + np.testing.assert_array_almost_equal(X[0], result) + + projector = MDS( + n_components=2, dissimilarity='precomputed', init_type='PCA', + n_init=1) + X = projector(Euclidean(self.iris)).embedding_ + np.testing.assert_array_almost_equal(X[0], result) + + projector = MDS( + n_components=2, dissimilarity='euclidean', init_type='PCA', + n_init=1) + X = projector(self.iris).embedding_ + np.testing.assert_array_almost_equal(X[0], result) + + projector = MDS( + n_components=6, dissimilarity='euclidean', init_type='PCA', + n_init=1) + X = projector(self.iris[:5]).embedding_ + result = np.array([-0.31871, -0.064644, 0.015653, -1.5e-08, -4.3e-11, 0]) + np.testing.assert_array_almost_equal(np.abs(X[0]), np.abs(result)) + + def test_isomap(self): + for i in range(1, 4): + self.__isomap_test_helper(self.ionosphere, n_com=i) + + def __isomap_test_helper(self, data, n_com): + isomap_fit = Isomap(n_neighbors=5, n_components=n_com) + isomap_fit = isomap_fit(data) + eshape = data.X.shape[0], n_com + self.assertEqual(eshape, isomap_fit.embedding_.shape) + + def test_lle(self): + for i in range(1, 4): + self.__lle_test_helper(self.ionosphere, n_com=i) + + def __lle_test_helper(self, data, n_com): + lle = LocallyLinearEmbedding(n_neighbors=5, n_components=n_com) + lle = lle(data) + + ltsa = LocallyLinearEmbedding(n_neighbors=5, n_components=n_com, + method="ltsa", + eigen_solver="dense") + ltsa = ltsa(data) + + hessian = LocallyLinearEmbedding(n_neighbors=15, n_components=n_com, + method="hessian", + eigen_solver="dense") + hessian = hessian(data) + + modified = LocallyLinearEmbedding(n_neighbors=5, n_components=n_com, + method="modified", + eigen_solver="dense") + modified = modified(data) + + self.assertEqual((data.X.shape[0], n_com), lle.embedding_.shape) + self.assertEqual((data.X.shape[0], n_com), ltsa.embedding_.shape) + self.assertEqual((data.X.shape[0], n_com), hessian.embedding_.shape) + self.assertEqual((data.X.shape[0], n_com), modified.embedding_.shape) + + def test_se(self): + for i in range(1, 4): + self.__se_test_helper(self.ionosphere, n_com=i) + + def __se_test_helper(self, data, n_com): + se = SpectralEmbedding(n_components=n_com, n_neighbors=5) + se = se(data) + self.assertEqual((data.X.shape[0], n_com), se.embedding_.shape) + + def test_torgerson(self): + data = self.ionosphere[::5] + dis = Euclidean(data) + + e1 = torgerson(dis, eigen_solver="auto") + e2 = torgerson(dis, eigen_solver="lapack") + e3 = torgerson(dis, eigen_solver="arpack") + + np.testing.assert_almost_equal(np.abs(e1), np.abs(e2)) + np.testing.assert_almost_equal(np.abs(e2), np.abs(e3)) + + with self.assertRaises(ValueError): + torgerson(dis, eigen_solver="madness") + + +class TestTSNE(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + + def test_fit(self): + n_components = 2 + tsne = TSNE(n_components=n_components) + model = tsne(self.iris) + + # The embedding should have the correct number of dimensions + self.assertEqual(model.embedding.X.shape, (self.iris.X.shape[0], n_components)) + + # The embedding should not contain NaNs + self.assertFalse(np.any(np.isnan(model.embedding.X))) + + # The embeddings in the table should match the embedding object + np.testing.assert_equal(model.embedding.X, model.embedding_) + + def test_transform(self): + # Set perplexity to avoid warnings + tsne = TSNE(perplexity=10) + model = tsne(self.iris[::2]) + new_embedding = model(self.iris[1::2]) + + # The new embedding should not contain NaNs + self.assertFalse(np.any(np.isnan(new_embedding.X))) + + def test_multiscale(self): + tsne = TSNE(perplexity=(10, 10), multiscale=True) + model = tsne(self.iris[::2]) + embedding = model(self.iris[1::2]) + self.assertFalse(np.any(np.isnan(embedding.X))) + + def test_continue_optimization(self): + tsne = TSNE(n_iter=100) + model = tsne(self.iris) + new_model = model.optimize(100, inplace=False) + + # If we don't do things inplace, then the instances should be different + self.assertIsNot(model, new_model) + self.assertIsNot(model.embedding, new_model.embedding) + self.assertIsNot(model.embedding_, new_model.embedding_) + + self.assertFalse(np.allclose(model.embedding.X, new_model.embedding.X), + 'Embedding should change after further optimization.') + + # The embeddings in the table should match the embedding object + np.testing.assert_equal(new_model.embedding.X, new_model.embedding_) + + def test_continue_optimization_inplace(self): + tsne = TSNE(n_iter=100) + model = tsne(self.iris) + new_model = model.optimize(100, inplace=True) + + # If we don't do things inplace, then the instances should be the same + self.assertIs(model, new_model) + self.assertIs(model.embedding, new_model.embedding) + self.assertIs(model.embedding_, new_model.embedding_) + + # The embeddings in the table should match the embedding object + np.testing.assert_equal(new_model.embedding.X, new_model.embedding_) + + def test_bh_correctness(self): + knn = KNeighborsClassifier(n_neighbors=5) + + # Set iterations to 0 so we check that the initialization is fairly random + tsne = TSNE(early_exaggeration_iter=0, n_iter=0, perplexity=30, + negative_gradient_method='bh', initialization='random', + random_state=0) + model = tsne(self.iris) + + # Evaluate KNN on the random initialization + knn.fit(model.embedding_, self.iris.Y) + predicted = knn.predict(model.embedding_) + self.assertTrue(accuracy_score(predicted, self.iris.Y) < 0.6) + + # 100 iterations should be enough for iris + model.optimize(n_iter=100, inplace=True) + + # Evaluate KNN on the tSNE embedding + knn.fit(model.embedding_, self.iris.Y) + predicted = knn.predict(model.embedding_) + self.assertTrue(accuracy_score(predicted, self.iris.Y) > 0.95) + + def test_fft_correctness(self): + knn = KNeighborsClassifier(n_neighbors=5) + + # Set iterations to 0 so we check that the initialization is fairly random + tsne = TSNE(early_exaggeration_iter=0, n_iter=0, perplexity=30, + negative_gradient_method='fft', initialization='random', + random_state=0) + model = tsne(self.iris) + + # Evaluate KNN on the random initialization + knn.fit(model.embedding_, self.iris.Y) + predicted = knn.predict(model.embedding_) + self.assertTrue(accuracy_score(predicted, self.iris.Y) < 0.6) + + # 100 iterations should be enough for iris + model.optimize(n_iter=100, inplace=True) + + # Evaluate KNN on the tSNE embedding + knn.fit(model.embedding_, self.iris.Y) + predicted = knn.predict(model.embedding_) + self.assertTrue(accuracy_score(predicted, self.iris.Y) > 0.95) diff --git a/pyminer2/tests/test_mean.py b/pyminer2/tests/test_mean.py new file mode 100644 index 0000000000000000000000000000000000000000..7e4b6779ad7c8e18495702339efe463dd8690a38 --- /dev/null +++ b/pyminer2/tests/test_mean.py @@ -0,0 +1,53 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np + +from Orange.data import Table +from Orange.regression import MeanLearner +from Orange.tests import test_filename + + +class TestMeanLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.learn = MeanLearner() + + def test_mean(self): + nrows = 1000 + ncols = 10 + x = np.random.randint(1, 4, (nrows, ncols)) + y = np.random.randint(0, 5, (nrows, 1)) / 3.0 + t = Table.from_numpy(None, x, y) + clf = self.learn(t) + + true_mean = np.average(y) + x2 = np.random.randint(1, 4, (nrows, ncols)) + y2 = clf(x2) + self.assertTrue(np.allclose(y2, true_mean)) + + def test_weights(self): + nrows = 100 + ncols = 10 + x = np.random.randint(1, 4, (nrows, ncols)) + y = np.random.randint(0, 5, (nrows, 1)) / 3.0 + heavy = 1 + w = ((y == heavy) * 123 + 1.0) / 124.0 + t = Table.from_numpy(None, x, y, W=w) + clf = self.learn(t) + + expected_mean = np.average(y, weights=w) + x2 = np.random.randint(1, 4, (nrows, ncols)) + y2 = clf(x2) + self.assertTrue(np.allclose(y2, expected_mean)) + + def test_empty(self): + autompg = Table(test_filename('datasets/imports-85.tab')) + clf = self.learn(autompg[:0]) + y = clf(autompg[0]) + self.assertEqual(y, 0) + + def test_discrete(self): + iris = Table('iris') + self.assertRaises(ValueError, self.learn, iris) diff --git a/pyminer2/tests/test_misc.py b/pyminer2/tests/test_misc.py new file mode 100644 index 0000000000000000000000000000000000000000..fe282bc598f31e8b76fccb40b1b42a6b354e713c --- /dev/null +++ b/pyminer2/tests/test_misc.py @@ -0,0 +1,36 @@ +import unittest + +from Orange.misc.cache import memoize_method, single_cache + + +class Calculator: + @memoize_method() + def my_sum(self, *nums): + return sum(nums) + + +@single_cache +def my_sum(*nums): + return sum(nums) + + +class TestCache(unittest.TestCase): + + def test_single_cache(self): + self.assertEqual(my_sum(1, 2, 3, 4, 5), 15) + self.assertEqual(my_sum(1, 2, 3, 4, 5), 15) + # Make sure different args produce different results + self.assertEqual(my_sum(1, 2, 3, 4), 10) + + def test_memoize_method(self): + calc = Calculator() + self.assertEqual(calc.my_sum(1, 2, 3, 4, 5), 15) + self.assertEqual(calc.my_sum.cache_info().currsize, 1) + self.assertEqual(calc.my_sum(1, 2, 3, 4, 5), 15) + self.assertEqual(calc.my_sum.cache_info().hits, 1) + # Make sure different args produce different results + self.assertEqual(calc.my_sum(1, 2, 3, 4), 10) + self.assertEqual(calc.my_sum.cache_info().currsize, 2) + # Clear cache + calc.my_sum.cache_clear() + self.assertEqual(calc.my_sum.cache_info().currsize, 0) diff --git a/pyminer2/tests/test_naive_bayes.py b/pyminer2/tests/test_naive_bayes.py new file mode 100644 index 0000000000000000000000000000000000000000..c54c7002ed66c0cd0d5b0e9b5d2450da24070297 --- /dev/null +++ b/pyminer2/tests/test_naive_bayes.py @@ -0,0 +1,331 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import Mock + +import numpy as np +import scipy.sparse as sp + +from Orange.classification import NaiveBayesLearner +from Orange.data import Table, Domain, DiscreteVariable, ContinuousVariable +from Orange.evaluation import CrossValidation, CA + + +# This class is used to force predict_storage to fall back to the slower +# procedure instead of calling `predict` +from Orange.tests import test_filename + + +class NotATable(Table): # pylint: disable=too-many-ancestors,abstract-method + pass + + +class TestNaiveBayesLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.data = data = Table('titanic') + cls.learner = NaiveBayesLearner() + cls.table = data[::20] + + def setUp(self): + self.model = self.learner(self.data) + + def test_NaiveBayes(self): + cv = CrossValidation(k=10) + results = cv(self.table, [self.learner]) + ca = CA(results) + self.assertGreater(ca, 0.7) + self.assertLess(ca, 0.9) + + cv = CrossValidation(k=10) + results = cv(Table("iris"), [self.learner]) + ca = CA(results) + self.assertGreater(ca, 0.7) + + def test_degenerate(self): + d = Domain((ContinuousVariable(name="A"), + ContinuousVariable(name="B"), + ContinuousVariable(name="C")), + DiscreteVariable(name="CLASS", values=["M", "F"])) + t = Table.from_list(d, [[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 0, 1]]) + nb = NaiveBayesLearner() + model = nb(t) + self.assertEqual(model.domain.attributes, ()) + self.assertEqual(model(t[0]), 1) + self.assertTrue(all(model(t) == 1)) + + def test_allnan_cv(self): + # GH 2740 + data = Table(test_filename('datasets/lenses.tab')) + cv = CrossValidation() + results = cv(data, [self.learner]) + self.assertFalse(any(results.failed)) + + def test_prediction_routing(self): + data = self.data + predict = self.model.predict = Mock(return_value=(data.Y, None)) + + self.model(data) + predict.assert_called() + predict.reset_mock() + + self.model(data.X) + predict.assert_called() + predict.reset_mock() + + self.model.predict_storage(data) + predict.assert_called() + predict.reset_mock() + + self.model.predict_storage(data[0]) + predict.assert_called() + + def test_compare_results_of_predict_and_predict_storage(self): + data2 = NotATable("titanic") + + self.model = self.learner(self.data[:50]) + predict = self.model.predict = Mock(side_effect=self.model.predict) + values, probs = self.model.predict_storage(self.data[50:]) + predict.assert_called() + predict.reset_mock() + values2, probs2 = self.model.predict_storage(data2[50:]) + predict.assert_not_called() + + np.testing.assert_equal(values, values2) + np.testing.assert_equal(probs, probs2) + + def test_predictions(self): + self._test_predictions(sparse=None) + self._test_predictions_with_absent_class(sparse=None) + + def test_predictions_csr_matrix(self): + self._test_predictions(sparse=sp.csr_matrix) + self._test_predictions_with_absent_class(sparse=sp.csr_matrix) + + def test_predictions_csc_matrix(self): + self._test_predictions(sparse=sp.csc_matrix) + self._test_predictions_with_absent_class(sparse=sp.csc_matrix) + + def _test_predictions(self, sparse): + x = np.array([ + [1, 0, 0], + [0, np.nan, 0], + [0, 1, 0], + [0, 0, 0], + [1, 2, 0], + [1, 1, 0], + [1, 2, 0], + [0, 1, 0]]) + if sparse is not None: + x = sparse(x) + + y = np.array([0, 0, 0, 1, 1, 1, 2, 2]) + domain = Domain( + [DiscreteVariable("a", values="ab"), + DiscreteVariable("b", values="abc"), + DiscreteVariable("c", values="a")], + DiscreteVariable("y", values="abc")) + data = Table.from_numpy(domain, x, y) + + model = self.learner(data) + np.testing.assert_almost_equal( + model.class_prob, + [4/11, 4/11, 3/11] + ) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[0]) * model.class_prob[:, None], + [[3/7, 2/7], [2/7, 3/7], [2/7, 2/7]]) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[1]) * model.class_prob[:, None], + [[2/5, 1/3, 1/5], [2/5, 1/3, 2/5], [1/5, 1/3, 2/5]]) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[2]) * model.class_prob[:, None], + [[4/11], [4/11], [3/11]]) + + test_x = np.array([[a, b, 0] for a in [0, 1] for b in [0, 1, 2]]) + # Classifiers reject csc matrices in the base class + # Naive bayesian classifier supports them if predict_storage is + # called directly, which we do below + if sparse is not None and sparse is not sp.csc_matrix: + test_x = sparse(test_x) + test_y = np.full((6, ), np.nan) + # The following was computed manually, too + exp_probs = np.array([ + [0.47368421052632, 0.31578947368421, 0.21052631578947], + [0.39130434782609, 0.26086956521739, 0.34782608695652], + [0.24324324324324, 0.32432432432432, 0.43243243243243], + [0.31578947368421, 0.47368421052632, 0.21052631578947], + [0.26086956521739, 0.39130434782609, 0.34782608695652], + [0.15000000000000, 0.45000000000000, 0.40000000000000] + ]) + + # Test the faster algorithm for Table (numpy matrices) + test_data = Table.from_numpy(domain, test_x, test_y) + probs = model(test_data, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_data) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_data, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test the slower algorithm for non-Table data (iteration in Python) + test_data = NotATable.from_numpy(domain, test_x, test_y) + probs = model(test_data, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_data) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_data, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test prediction directly on numpy + probs = model(test_x, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_x) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_x, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test prediction on instances + for inst, exp_prob in zip(test_data, exp_probs): + np.testing.assert_almost_equal( + model(inst, ret=model.Probs), + exp_prob) + self.assertEqual(model(inst), np.argmax(exp_prob)) + value, prob = model(inst, ret=model.ValueProbs) + np.testing.assert_almost_equal(prob, exp_prob) + self.assertEqual(value, np.argmax(exp_prob)) + + # Test prediction by directly calling predict. This is needed to test + # csc_matrix, but doesn't hurt others + if sparse is sp.csc_matrix: + test_x = sparse(test_x) + values, probs = model.predict(test_x) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + def _test_predictions_with_absent_class(self, sparse): + """Empty classes should not affect predictions""" + x = np.array([ + [1, 0, 0], + [0, np.nan, 0], + [0, 1, 0], + [0, 0, 0], + [1, 2, 0], + [1, 1, 0], + [1, 2, 0], + [0, 1, 0]]) + if sparse is not None: + x = sparse(x) + + y = np.array([0, 0, 0, 2, 2, 2, 3, 3]) + domain = Domain( + [DiscreteVariable("a", values="ab"), + DiscreteVariable("b", values="abc"), + DiscreteVariable("c", values="a")], + DiscreteVariable("y", values="abcd")) + data = Table.from_numpy(domain, x, y) + + model = self.learner(data) + np.testing.assert_almost_equal( + model.class_prob, + [4/11, 0, 4/11, 3/11] + ) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[0]) * model.class_prob[:, None], + [[3/7, 2/7], [0, 0], [2/7, 3/7], [2/7, 2/7]]) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[1]) * model.class_prob[:, None], + [[2/5, 1/3, 1/5], [0, 0, 0], [2/5, 1/3, 2/5], [1/5, 1/3, 2/5]]) + np.testing.assert_almost_equal( + np.exp(model.log_cont_prob[2]) * model.class_prob[:, None], + [[4/11], [0], [4/11], [3/11]]) + + test_x = np.array([[a, b, 0] for a in [0, 1] for b in [0, 1, 2]]) + # Classifiers reject csc matrices in the base class + # Naive bayesian classifier supports them if predict_storage is + # called directly, which we do below + if sparse is not None and sparse is not sp.csc_matrix: + test_x = sparse(test_x) + test_y = np.full((6, ), np.nan) + # The following was computed manually, too + exp_probs = np.array([ + [0.47368421052632, 0, 0.31578947368421, 0.21052631578947], + [0.39130434782609, 0, 0.26086956521739, 0.34782608695652], + [0.24324324324324, 0, 0.32432432432432, 0.43243243243243], + [0.31578947368421, 0, 0.47368421052632, 0.21052631578947], + [0.26086956521739, 0, 0.39130434782609, 0.34782608695652], + [0.15000000000000, 0, 0.45000000000000, 0.40000000000000] + ]) + + # Test the faster algorithm for Table (numpy matrices) + test_data = Table.from_numpy(domain, test_x, test_y) + probs = model(test_data, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_data) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_data, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test the slower algorithm for non-Table data (iteration in Python) + test_data = NotATable.from_numpy(domain, test_x, test_y) + probs = model(test_data, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_data) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_data, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test prediction directly on numpy + probs = model(test_x, ret=model.Probs) + np.testing.assert_almost_equal(exp_probs, probs) + values = model(test_x) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + values, probs = model(test_x, ret=model.ValueProbs) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + # Test prediction on instances + for inst, exp_prob in zip(test_data, exp_probs): + np.testing.assert_almost_equal( + model(inst, ret=model.Probs), + exp_prob) + self.assertEqual(model(inst), np.argmax(exp_prob)) + value, prob = model(inst, ret=model.ValueProbs) + np.testing.assert_almost_equal(prob, exp_prob) + self.assertEqual(value, np.argmax(exp_prob)) + + # Test prediction by directly calling predict. This is needed to test + # csc_matrix, but doesn't hurt others + if sparse is sp.csc_matrix: + test_x = sparse(test_x) + values, probs = model.predict(test_x) + np.testing.assert_almost_equal(exp_probs, probs) + np.testing.assert_equal(values, np.argmax(exp_probs, axis=1)) + + def test_no_attributes(self): + y = np.array([0, 0, 0, 1, 1, 1, 2, 2]) + domain = Domain([], DiscreteVariable("y", values="abc")) + data = Table.from_numpy(domain, np.zeros((len(y), 0)), y.T) + model = self.learner(data) + np.testing.assert_almost_equal( + model.predict_storage(np.zeros((5, 0)))[1], + [[4/11, 4/11, 3/11]] * 5 + ) + + def test_no_targets(self): + x = np.array([[0], [1], [2]]) + y = np.full(3, np.nan) + domain = Domain([DiscreteVariable("x", values="abc")], + DiscreteVariable("y", values="abc")) + data = Table.from_numpy(domain, x, y) + self.assertRaises(ValueError, self.learner, data) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_neural_network.py b/pyminer2/tests/test_neural_network.py new file mode 100644 index 0000000000000000000000000000000000000000..e16750e6eabc73e5716b3670350ec1e56ff170db --- /dev/null +++ b/pyminer2/tests/test_neural_network.py @@ -0,0 +1,65 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import warnings + +from sklearn.exceptions import ConvergenceWarning + +from Orange.data import Table +from Orange.classification import NNClassificationLearner +from Orange.modelling import NNLearner, ConstantLearner +from Orange.regression import NNRegressionLearner +from Orange.evaluation import CA, CrossValidation, MSE + + +class TestNNLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.housing = Table('housing') + cls.learner = NNLearner() + + def setUp(self): + # Convergence warnings are irrelevant for these tests + warnings.filterwarnings("ignore", ".*", ConvergenceWarning) + super().setUp() + + def test_NN_classification(self): + cv = CrossValidation(k=3) + results = cv(self.iris, [NNClassificationLearner()]) + ca = CA(results) + self.assertGreater(ca, 0.8) + self.assertLess(ca, 0.99) + + def test_NN_regression(self): + const = ConstantLearner() + cv = CrossValidation(k=3) + results = cv(self.housing, [NNRegressionLearner(), const]) + mse = MSE() + res = mse(results) + self.assertLess(res[0], 35) + self.assertLess(res[0], res[1]) + + def test_NN_model(self): + cv = CrossValidation(k=3) + results = cv(self.iris, [self.learner]) + self.assertGreater(CA(results), 0.90) + cv = CrossValidation(k=3) + results = cv(self.housing, [self.learner]) + mse = MSE() + res = mse(results) + self.assertLess(res[0], 35) + + def test_NN_classification_predict_single_instance(self): + lrn = NNClassificationLearner() + clf = lrn(self.iris) + for ins in self.iris[::20]: + clf(ins) + _, _ = clf(ins, clf.ValueProbs) + + def test_NN_regression_predict_single_instance(self): + lrn = NNRegressionLearner() + clf = lrn(self.housing) + for ins in self.housing[::20]: + clf(ins) diff --git a/pyminer2/tests/test_normalize.py b/pyminer2/tests/test_normalize.py new file mode 100644 index 0000000000000000000000000000000000000000..1b93a2d231121dec113717d4a1ee49372ee8776d --- /dev/null +++ b/pyminer2/tests/test_normalize.py @@ -0,0 +1,159 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +import scipy.sparse as sp + +from Orange.data import Table, Domain, ContinuousVariable +from Orange.preprocess import Normalize +from Orange.tests import test_filename + + +class TestNormalizer(unittest.TestCase): + def compare_tables(self, dataNorm, solution): + for i in range(len(dataNorm)): + for j in range(len(dataNorm[i])): + if type(solution[i][j]) == float: + self.assertAlmostEqual(dataNorm[i, j], solution[i][j], places=3) + else: + self.assertEqual(dataNorm[i, j], solution[i][j]) + self.assertEqual([attr.name for attr in dataNorm.domain.attributes], + ["c1", "c2", "d1", "d2", "n1", "n2", "c3", "d3", "c4"]) + self.assertEqual([attr.name for attr in dataNorm.domain.class_vars], + ["cl1", "cl2"]) + @classmethod + def setUpClass(cls): + cls.data = Table(test_filename("datasets/test5.tab")) + + def test_normalize_default(self): + normalizer = Normalize() + data_norm = normalizer(self.data) + solution = [[0., 1.225, 'a', 'a', '?', 'a', 1.225, 'a', '?', 'a', 2], + [0., -1.225, 'a', 'b', -1., '?', 0., 'b', '?', 'b', 0], + [0., 0., 'a', 'b', 1., 'b', -1.225, 'c', '?', 'c', 1]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_by_sd(self): + normalizer = Normalize(zero_based=False, + norm_type=Normalize.NormalizeBySD, + transform_class=False) + data_norm = normalizer(self.data) + solution = [[0., 1.225, 'a', 'a', '?', 'a', 1.225, 'a', '?', 'a', 2], + [0., -1.225, 'a', 'b', -1., '?', 0., 'b', '?', 'b', 0], + [0., 0., 'a', 'b', 1., 'b', -1.225, 'c', '?', 'c', 1]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_class(self): + normalizer = Normalize(zero_based=True, + norm_type=Normalize.NormalizeBySD, + transform_class=True) + data_norm = normalizer(self.data) + solution = [[0., 1.225, 'a', 'a', '?', 'a', 1.225, 'a', '?', 'a', 1.225], + [0., -1.225, 'a', 'b', -1., '?', 0., 'b', '?', 'b', -1.225], + [0., 0., 'a', 'b', 1., 'b', -1.225, 'c', '?', 'c', 0.]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_by_span(self): + normalizer = Normalize(zero_based=False, + norm_type=Normalize.NormalizeBySpan, + transform_class=False) + data_norm = normalizer(self.data) + solution = [[0., 1., 'a', 'a', '?', 'a', 1., 'a', '?', 'a', 2.], + [0., -1., 'a', 'b', -1., '?', 0., 'b', '?', 'b', 0.], + [0., 0., 'a', 'b', 1., 'b', -1., 'c', '?', 'c', 1.]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_by_span_zero(self): + normalizer = Normalize(zero_based=True, + norm_type=Normalize.NormalizeBySpan, + transform_class=False) + data_norm = normalizer(self.data) + solution = [[0., 1., 'a', 'a', '?', 'a', 1., 'a', '?', 'a', 2.], + [0., 0., 'a', 'b', 0., '?', 0.5, 'b', '?', 'b', 0.], + [0., 0.5, 'a', 'b', 1., 'b', 0., 'c', '?', 'c', 1.]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_by_span_class(self): + normalizer = Normalize(zero_based=False, + norm_type=Normalize.NormalizeBySpan, + transform_class=True) + data_norm = normalizer(self.data) + solution = [[0., 1., 'a', 'a', '?', 'a', 1., 'a', '?', 'a', 1.], + [0., -1., 'a', 'b', -1., '?', 0., 'b', '?', 'b', -1.], + [0., 0., 'a', 'b', 1., 'b', -1., 'c', '?', 'c', 0.]] + self.compare_tables(data_norm, solution) + + def test_normalize_transform_by_span_zero_class(self): + normalizer = Normalize(zero_based=True, + norm_type=Normalize.NormalizeBySpan, + transform_class=True) + data_norm = normalizer(self.data) + solution = [[0., 1., 'a', 'a', '?', 'a', 1., 'a', '?', 'a', 1.], + [0., 0., 'a', 'b', 0., '?', 0.5, 'b', '?', 'b', 0.], + [0., 0.5, 'a', 'b', 1., 'b', 0., 'c', '?', 'c', 0.5]] + self.compare_tables(data_norm, solution) + + def test_normalize_sparse(self): + domain = Domain([ContinuousVariable(str(i)) for i in range(3)]) + # pylint: disable=bad-whitespace + X = np.array([ + [0, -1, -2], + [0, 1, 2], + ]) + data = Table.from_numpy(domain, X).to_sparse() + + # pylint: disable=bad-whitespace + solution = sp.csr_matrix(np.array([ + [0, -1, -1], + [0, 1, 1], + ])) + + normalizer = Normalize() + normalized = normalizer(data) + self.assertEqual((normalized.X != solution).nnz, 0) + + # raise error for non-zero offsets + data.X = sp.csr_matrix(np.array([ + [0, 0, 0], + [0, 1, 3], + [0, 2, 4], + ])) + with self.assertRaises(ValueError): + normalizer(data) + + def test_skip_normalization(self): + data = self.data.copy() + for attr in data.domain.attributes: + attr.attributes = {'skip-normalization': True} + + normalizer = Normalize() + normalized = normalizer(data) + np.testing.assert_array_equal(data.X, normalized.X) + + def test_datetime_normalization(self): + data = Table(test_filename("datasets/test10.tab")) + normalizer = Normalize(zero_based=False, + norm_type=Normalize.NormalizeBySD, + transform_class=False) + data_norm = normalizer(data) + solution = [[0., '1995-01-21', 'a', 'a', '?', 'a', 1.225, 'a', '?', 'a', 2], + [0., '2003-07-23', 'a', 'b', -1., '?', 0., 'b', '?', 'b', 0], + [0., '1967-03-12', 'a', 'b', 1., 'b', -1.225, 'c', '?', 'c', 1]] + self.compare_tables(data_norm, solution) + + def test_retain_vars_attributes(self): + data = Table("iris") + attributes = {"foo": "foo", "baz": 1} + data.domain.attributes[0].attributes = attributes + self.assertDictEqual( + Normalize(norm_type=Normalize.NormalizeBySD)( + data).domain.attributes[0].attributes, attributes) + self.assertDictEqual( + Normalize(norm_type=Normalize.NormalizeBySpan)( + data).domain.attributes[0].attributes, attributes) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_orange.py b/pyminer2/tests/test_orange.py new file mode 100644 index 0000000000000000000000000000000000000000..2db00be2102459aa743d7366547ae15814bf9b90 --- /dev/null +++ b/pyminer2/tests/test_orange.py @@ -0,0 +1,12 @@ +import unittest + + +class TestOrange(unittest.TestCase): + def test_orange_has_modules(self): + import pkgutil + import Orange + unimported = ['canvas', 'datasets', 'testing', 'tests', 'setup', + 'util', 'widgets'] + for _, name, __ in pkgutil.iter_modules(Orange.__path__): + if name not in unimported: + self.assertIn(name, Orange.__dict__) diff --git a/pyminer2/tests/test_orangetree.py b/pyminer2/tests/test_orangetree.py new file mode 100644 index 0000000000000000000000000000000000000000..a1d4a4e5a0362651ae3bac750b4686905c0ab0c5 --- /dev/null +++ b/pyminer2/tests/test_orangetree.py @@ -0,0 +1,450 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +import scipy.sparse as sp + +from Orange.data import Table, Domain, DiscreteVariable, ContinuousVariable +from Orange.classification.tree import \ + TreeModel, Node, DiscreteNode, MappedDiscreteNode, NumericNode +from Orange.tests import test_filename + + +class TestTree: + @classmethod + def setUpClass(cls): + cls.no_pruning_args = {} + + @classmethod + def all_nodes(cls, node): + yield node + for child in node.children: + if child: + yield from cls.all_nodes(child) + + def test_get_tree(self): + learn = self.TreeLearner() + clf = learn(self.data) + self.assertIsInstance(clf, TreeModel) + + def test_full_tree(self): + table = self.data + learn = self.TreeLearner(**self.no_pruning_args) + clf = learn(table) + pred = clf(table) + self.assertTrue(np.all(table.Y.flatten() == pred)) + + def test_min_samples_split(self): + clf = self.TreeLearner( + min_samples_split=10, **self.no_pruning_args)(self.data) + self.assertTrue( + all(not node.children or len(node.subset) >= 10 + for node in self.all_nodes(clf.root))) + + def test_min_samples_leaf(self): + # This test is slow, but it has a good tendency to fail at extreme + # conditions not thought of in advance and thus not covered in other + # tests + for lim in (1, 2, 30): + args = dict(min_samples_split=2, min_samples_leaf=lim) + args.update(self.no_pruning_args) + clf = self.TreeLearner(binarize=False, **args)(self.data_mixed) + self.assertTrue(all(len(node.subset) >= lim + for node in self.all_nodes(clf.root) + if node)) + clf = self.TreeLearner(binarize=True, **args)(self.data_mixed) + self.assertTrue(all(len(node.subset) >= lim + for node in self.all_nodes(clf.root) + if node)) + + def test_max_depth(self): + for i in (1, 2, 5): + tree = self.TreeLearner(max_depth=i)(self.data) + self.assertEqual(tree.depth(), i) + + def test_refuse_binarize_too_many_values(self): + clf = self.TreeLearner(binarize=True) + lim = clf.MAX_BINARIZATION + + domain = Domain( + [DiscreteVariable("x", ("v{}".format(i) for i in range(lim + 1)))], + self.class_var) + data = Table(domain, np.zeros((100, 2))) + + clf.binarize = False + clf(data) + clf.binarize = True + self.assertRaises(ValueError, clf, data) + + domain = Domain( + [DiscreteVariable("x", ("v{}".format(i) for i in range(lim)))], + self.class_var) + data = Table(domain, np.zeros((100, 2))) + clf.binarize = True + clf(data) + clf.binarize = False + clf(data) + + def test_find_mapping(self): + clf = self.TreeLearner(binarize=True) + + domain = Domain([DiscreteVariable("x", values="abcdefgh"), + ContinuousVariable("r1"), + DiscreteVariable("r2", values="abcd")], + self.class_var) + col_x = np.arange(80) % 8 + for mapping in (np.array([0, 1, 0, 1, 0, 1, 0, 1]), + np.array([0, 0, 0, 0, 0, 1, 1, 0]), + np.array([0, 0, 1, 0, 0, 0, 0, 0]), + np.array([1, 0, 0, 0, 0, 0, 0, 0]), + np.array([0, 0, 0, 0, 0, 0, 0, 1]), + np.array([1, 1, 1, 1, 1, 1, 1, 0]), + np.array([0, 1, 1, 1, 1, 1, 1, 1]), + np.array([1, 1, 1, 1, 0, 1, 1, 1])): + data = Table(domain, + np.vstack((col_x, + np.random.random(80), + np.random.randint(0, 3, 80).astype(float), + mapping[col_x],)).T) + root = clf(data).root + self.assertIsInstance(root, MappedDiscreteNode) + self.assertEqual(root.attr_idx, 0) + found = root.mapping if root.mapping[0] == 0 else 1 - root.mapping + mapping = mapping if mapping[0] == 0 else 1 - mapping + np.testing.assert_equal(found, mapping) + self.assertEqual(len(root.children), 2) + self.assertIsInstance(root.children[0], Node) + self.assertIsInstance(root.children[1], Node) + + def test_find_threshold(self): + clf = self.TreeLearner() + + domain = Domain([ContinuousVariable("x"), + DiscreteVariable("r1", values="abcd"), + ContinuousVariable("r2")], + self.class_var) + + col_x = np.arange(80) + np.random.shuffle(col_x) + data = Table(domain, + np.vstack((col_x, + np.random.randint(0, 3, 80).astype(float), + np.random.random(80), + col_x > 30,)).T) + root = clf(data).root + self.assertIsInstance(root, NumericNode) + self.assertEqual(root.attr_idx, 0) + self.assertEqual(root.threshold, 30) + self.assertEqual(len(root.children), 2) + self.assertIsInstance(root.children[0], Node) + self.assertIsInstance(root.children[1], Node) + + def test_no_data(self): + clf = self.TreeLearner() + + domain = Domain([DiscreteVariable("r1", values="ab"), + DiscreteVariable("r2", values="abcd"), + ContinuousVariable("r3")], + self.class_var) + + data = Table.from_domain(domain) + tree = clf(data) + self.assertIsInstance(tree.root, Node) + np.testing.assert_almost_equal(tree.predict(np.array([[0., 0., 0.]])), + self.blind_prediction) + + def test_all_values_missing(self): + clf = self.TreeLearner() + + domain = Domain([DiscreteVariable("r1", values="ab"), + DiscreteVariable("r2", values="abcd"), + ContinuousVariable("r3")], + self.class_var) + a = np.empty((10, 4)) + a[:, :3] = np.nan + a[:, 3] = np.arange(10) % 2 + data = Table(domain, a) + for clf.binarize in (False, True): + tree = clf(data) + self.assertIsInstance(tree.root, Node) + np.testing.assert_almost_equal( + tree.predict(np.array([[0., 0., 0.]])), + self.prediction_on_0_1) + + def test_single_valued_attr(self): + clf = self.TreeLearner() + domain = Domain([DiscreteVariable("r1", values="a")], + self.class_var) + data = Table(domain, np.array([[0, 0], [0, 1]])) + tree = clf(data) + self.assertIsInstance(tree.root, Node) + np.testing.assert_almost_equal(tree.predict(np.array([[0., 0., 0.]])), + self.prediction_on_0_1) + + def test_allow_null_nodes(self): + domain = Domain([DiscreteVariable("x", values="abc"), + ContinuousVariable("r1"), + DiscreteVariable("r2", values="ab")], + self.class_var) + xy = np.array([[0, 0, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1], [1, 1, 1, 1]]) + data = Table(domain, xy) + clf = self.TreeLearner(binarize=False) + tree = clf(data) + root = tree.root + self.assertIsInstance(root, DiscreteNode) + self.assertEqual(root.attr_idx, 0) + self.assertIsNotNone(root.children[0]) + self.assertIsNotNone(root.children[1]) + self.assertIsNone(root.children[2]) + np.testing.assert_equal(tree(data), data.Y) + + +class TestClassifier(TestTree, unittest.TestCase): + from Orange.classification import TreeLearner + + @classmethod + def setUpClass(cls): + unittest.TestCase.setUpClass() + TestTree.setUpClass() + + cls.no_pruning_args = {'sufficient_majority': 1} + + cls.data = Table('iris') # continuous attributes + cls.data_mixed = Table('heart_disease') # mixed + cls.class_var = DiscreteVariable("y", values="nyx") + cls.blind_prediction = np.ones((1, 3)) / 3 + cls.prediction_on_0_1 = np.array([[0.5, 0.5, 0]]) + + +class TestRegressor(TestTree, unittest.TestCase): + from Orange.regression import TreeLearner + + @classmethod + def setUpClass(cls): + unittest.TestCase.setUpClass() + TestTree.setUpClass() + + cls.data = Table("housing") + imports = Table(test_filename("datasets/imports-85.tab")) + new_domain = Domain([attr for attr in imports.domain.attributes + if attr.is_continuous or len(attr.values) <= 16], + imports.domain.class_var) + cls.data_mixed = imports.transform(new_domain) + + cls.class_var = ContinuousVariable("y") + cls.blind_prediction = 0 + cls.prediction_on_0_1 = 0.5 + + +class TestNodes(unittest.TestCase): + def test_node(self): + var = ContinuousVariable("y") + node = Node(var, 42, "foo") + self.assertEqual(node.attr, var) + self.assertEqual(node.attr_idx, 42) + self.assertEqual(node.value, "foo") + self.assertEqual(node.children, []) + np.testing.assert_equal(node.subset, np.array([], dtype=np.int32)) + + self.assertTrue(np.isnan(node.descend([]))) + + def test_discrete_node(self): + var = DiscreteVariable("y", values="abc") + node = DiscreteNode(var, 2, "foo") + self.assertEqual(node.attr, var) + self.assertEqual(node.attr_idx, 2) + self.assertEqual(node.value, "foo") + self.assertEqual(node.children, []) + np.testing.assert_equal(node.subset, np.array([], dtype=np.int32)) + + self.assertEqual(node.descend([3, 4, 1, 6]), 1) + self.assertTrue(np.isnan(node.descend([3, 4, float("nan"), 6]))) + + def test_mapped_node(self): + var = DiscreteVariable("y", values="abc") + node = MappedDiscreteNode(var, 2, np.array([1, 1, 0]), "foo") + self.assertEqual(node.attr, var) + self.assertEqual(node.attr_idx, 2) + self.assertEqual(node.value, "foo") + self.assertEqual(node.children, []) + np.testing.assert_equal(node.subset, np.array([], dtype=np.int32)) + + self.assertEqual(node.descend([3, 4, 0, 6]), 1) + self.assertEqual(node.descend([3, 4, 1, 6]), 1) + self.assertEqual(node.descend([3, 4, 2, 6]), 0) + self.assertTrue(np.isnan(node.descend([3, 4, float("nan"), 6]))) + + mapping, branches = MappedDiscreteNode.branches_from_mapping( + np.array([2, 3, 1, 1, 0, 1, 4, 2]), int("1001", 2), 6) + np.testing.assert_equal( + mapping, np.array([1, 0, 0, 1, 0, 0], dtype=np.int16)) + np.testing.assert_equal( + branches, np.array([0, 1, 0, 0, 1, 0, 0, 0], dtype=np.int16)) + + def test_numeric_node(self): + var = ContinuousVariable("y") + node = NumericNode(var, 2, 42, "foo") + self.assertEqual(node.attr, var) + self.assertEqual(node.attr_idx, 2) + self.assertEqual(node.value, "foo") + self.assertEqual(node.children, []) + np.testing.assert_equal(node.subset, np.array([], dtype=np.int32)) + + self.assertEqual(node.descend([3, 4, 0, 6]), 0) + self.assertEqual(node.descend([3, 4, 42, 6]), 0) + self.assertEqual(node.descend([3, 4, 42.1, 6]), 1) + self.assertTrue(np.isnan(node.descend([3, 4, float("nan"), 6]))) + + +class TestTreeModel(unittest.TestCase): + def setUp(self): + """ + Construct a tree with v1 as a root, and v2 and v3 as left and right + child. + """ + # pylint: disable=invalid-name + v1 = self.v1 = ContinuousVariable("v1") + v2 = self.v2 = DiscreteVariable("v2", "abc") + v3 = self.v3 = DiscreteVariable("v3", "def") + y = self.y = ContinuousVariable("y") + self.domain = Domain([v1, v2, v3], y) + self.data = Table(self.domain, np.arange(40).reshape(10, 4)) + self.root = NumericNode(v1, 0, 13, np.array([0., 42])) + self.root.subset = np.array([], dtype=np.int32) + left = DiscreteNode(v2, 1, np.array([1, 42])) + left.children = [Node(None, None, np.array([x, 42])) for x in [2, 3, 4]] + right = MappedDiscreteNode(v3, 2, np.array([1, 1, 0]), + np.array([5, 42])) + right.children = [Node(None, None, np.array([x, 42])) for x in [6, 7]] + self.root.children = [left, right] + + def test_compile_and_run_cont(self): + # I investigate, I have a warrant + # pylint: disable=protected-access + model = TreeModel(self.data, self.root) + expected_values = np.vstack((np.arange(8), [42] * 8)).T + np.testing.assert_equal(model._values, expected_values) + self.assertEqual(model._thresholds[0], 13) + self.assertEqual(model._thresholds.shape, (8,)) + + nan = float("nan") + x = np.array( + [[nan, 0, 0], + [13, nan, 0], + [13, 0, 0], + [13, 1, 0], + [13, 2, 0], + [14, 2, nan], + [14, 2, 2], + [14, 2, 1]], dtype=float + ) + np.testing.assert_equal(model.get_values(x), expected_values) + np.testing.assert_equal(model.get_values_in_python(x), expected_values) + np.testing.assert_equal(model.get_values_by_nodes(x), expected_values) + np.testing.assert_equal(model.predict(x), np.arange(8).astype(int)) + + v1 = ContinuousVariable("d1") + v2 = DiscreteVariable("d2", "abc") + v3 = DiscreteVariable("d3", "def") + y = DiscreteVariable("dy") + domain = Domain([v1, v2, v3], y) + data = Table(domain, np.zeros((10, 4))) + root = NumericNode(v1, 0, 13, np.array([0., 42])) + left = DiscreteNode(v2, 1, np.array([1, 42])) + left.children = [Node(None, None, np.array([x, 42])) for x in [2, 3, 4]] + right = MappedDiscreteNode(v3, 2, np.array([1, 1, 0]), + np.array([5, 42])) + right.children = [Node(None, None, np.array([x, 42])) for x in [6, 7]] + root.children = [left, right] + + model = TreeModel(data, root) + normalized = \ + expected_values / np.sum(expected_values, axis=1)[:, np.newaxis] + np.testing.assert_equal(model.predict(x), normalized) + + def test_null_nodes(self): + a = DiscreteVariable("d4", "ab") + y = ContinuousVariable("ey") + domain = Domain([a], y) + data = Table.from_domain(domain) + values = np.array([[42., 43], [44, 45]]) + root = DiscreteNode(a, 0, values[1]) + root.children = [Node(None, -1, values[0]), None] + model = TreeModel(data, root) + x = np.array([[0.], [1]]) + np.testing.assert_equal(model.get_values(x), values) + np.testing.assert_equal(model.get_values_in_python(x), values) + np.testing.assert_equal(model.get_values_by_nodes(x), values) + + def test_methods(self): + model = TreeModel(self.data, self.root) + self.assertEqual(model.node_count(), 8) + self.assertEqual(model.leaf_count(), 5) + self.assertEqual(model.depth(), 2) + self.assertIs(model.root, self.root) + + left = self.root.children[0] + left.subset = np.array([2, 3]) + subset = model.get_instances([self.root, left]) + self.assertIsInstance(subset, Table) + self.assertEqual(len(subset), 2) + np.testing.assert_equal(subset.X, np.array([[8, 9, 10], [12, 13, 14]])) + np.testing.assert_equal(subset.Y, np.array([11, 15])) + + def test_print(self): + model = TreeModel(self.data, self.root) + self.assertEqual(model.print_tree(), """ [ 1 42] v1 ≤ 13 + [ 2 42] v2 a + [ 3 42] v2 b + [ 4 42] v2 c + [ 5 42] v1 > 13 + [ 6 42] v3 f + [ 7 42] v3 d or e +""") + + def test_compile_and_run_cont_sparse(self): + # pylint: disable=protected-access + model = TreeModel(self.data, self.root) + expected_values = np.vstack((np.arange(8), [42] * 8)).T + np.testing.assert_equal(model._values, expected_values) + self.assertEqual(model._thresholds[0], 13) + self.assertEqual(model._thresholds.shape, (8,)) + + nan = float("nan") + x = sp.csr_matrix(np.array( + [[nan, 0, 0], + [13, nan, 0], + [13, 0, 0], + [13, 1, 0], + [13, 2, 0], + [14, 2, nan], + [14, 2, 2], + [14, 2, 1]], dtype=float + )) + np.testing.assert_equal(model.get_values(x), expected_values) + + x = sp.csc_matrix(np.array( + [[nan, 0, 0], + [13, nan, 0], + [13, 0, 0], + [13, 1, 0], + [13, 2, 0], + [14, 2, nan], + [14, 2, 2], + [14, 2, 1]], dtype=float + )) + np.testing.assert_equal(model.get_values(x), expected_values) + + x = sp.lil_matrix(np.array( + [[nan, 0, 0], + [13, nan, 0], + [13, 0, 0], + [13, 1, 0], + [13, 2, 0], + [14, 2, nan], + [14, 2, 2], + [14, 2, 1]], dtype=float + )) + np.testing.assert_equal(model.get_values(x), expected_values) diff --git a/pyminer2/tests/test_pca.py b/pyminer2/tests/test_pca.py new file mode 100644 index 0000000000000000000000000000000000000000..2375a6239e2a0c5d2e8d0be9c5f240d47b82d4b1 --- /dev/null +++ b/pyminer2/tests/test_pca.py @@ -0,0 +1,259 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import pickle +import unittest +from unittest.mock import MagicMock + +import numpy as np +from sklearn import __version__ as sklearn_version +from sklearn.utils import check_random_state + +from Orange.data import Table, Domain +from Orange.preprocess import Continuize, Normalize +from Orange.projection import pca, PCA, SparsePCA, IncrementalPCA, TruncatedSVD +from Orange.tests import test_filename + + +class TestPCA(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.ionosphere = Table(test_filename('datasets/ionosphere.tab')) + cls.iris = Table('iris') + cls.zoo = Table('zoo') + + def test_pca(self): + data = self.ionosphere + self.__pca_test_helper(data, n_com=3, min_xpl_var=0.5) + self.__pca_test_helper(data, n_com=10, min_xpl_var=0.7) + self.__pca_test_helper(data, n_com=32, min_xpl_var=1) + + def __pca_test_helper(self, data, n_com, min_xpl_var): + pca = PCA(n_components=n_com) + pca_model = pca(data) + pca_xpl_var = np.sum(pca_model.explained_variance_ratio_) + self.assertGreaterEqual(pca_xpl_var + 1e-6, min_xpl_var) + self.assertEqual(n_com, pca_model.n_components) + self.assertEqual((n_com, data.X.shape[1]), pca_model.components_.shape) + proj = np.dot(data.X - pca_model.mean_, pca_model.components_.T) + np.testing.assert_almost_equal(pca_model(data).X, proj) + + def test_sparse_pca(self): + data = self.ionosphere[:100] + self.__sparse_pca_test_helper(data, n_com=3, max_err=1500) + self.__sparse_pca_test_helper(data, n_com=10, max_err=1000) + self.__sparse_pca_test_helper(data, n_com=32, max_err=500) + + def __sparse_pca_test_helper(self, data, n_com, max_err): + sparse_pca = SparsePCA(n_components=n_com, ridge_alpha=0.001, random_state=0) + pca_model = sparse_pca(data) + self.assertEqual(n_com, pca_model.n_components) + self.assertEqual((n_com, data.X.shape[1]), pca_model.components_.shape) + self.assertLessEqual(pca_model.error_[-1], max_err) + + def test_randomized_pca(self): + data = self.ionosphere + self.__rnd_pca_test_helper(data, n_com=3, min_xpl_var=0.5) + self.__rnd_pca_test_helper(data, n_com=10, min_xpl_var=0.7) + self.__rnd_pca_test_helper(data, n_com=32, min_xpl_var=0.98) + + def __rnd_pca_test_helper(self, data, n_com, min_xpl_var): + rnd_pca = PCA(n_components=n_com, svd_solver='randomized') + pca_model = rnd_pca(data) + pca_xpl_var = np.sum(pca_model.explained_variance_ratio_) + self.assertGreaterEqual(pca_xpl_var, min_xpl_var) + self.assertEqual(n_com, pca_model.n_components) + self.assertEqual((n_com, data.X.shape[1]), pca_model.components_.shape) + proj = np.dot(data.X - pca_model.mean_, pca_model.components_.T) + np.testing.assert_almost_equal(pca_model(data).X, proj) + + def test_improved_randomized_pca_properly_called(self): + # It doesn't matter what we put into the matrix + x_ = np.random.normal(0, 1, (100, 20)) + x = Table.from_numpy(Domain.from_numpy(x_), x_) + + pca.randomized_pca = MagicMock(wraps=pca.randomized_pca) + PCA(10, svd_solver="randomized", random_state=42)(x) + pca.randomized_pca.assert_called_once() + + pca.randomized_pca.reset_mock() + PCA(10, svd_solver="arpack", random_state=42)(x) + pca.randomized_pca.assert_not_called() + + def test_improved_randomized_pca_dense_data(self): + """Randomized PCA should work well on dense data.""" + random_state = check_random_state(42) + + # Let's take a tall, skinny matrix + x_ = random_state.normal(0, 1, (100, 20)) + x = Table.from_numpy(Domain.from_numpy(x_), x_) + + pca = PCA(10, svd_solver="full", random_state=random_state)(x) + rpca = PCA(10, svd_solver="randomized", random_state=random_state)(x) + + np.testing.assert_almost_equal( + pca.components_, rpca.components_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.explained_variance_, rpca.explained_variance_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.singular_values_, rpca.singular_values_, decimal=8 + ) + + # And take a short, fat matrix + x_ = random_state.normal(0, 1, (20, 100)) + x = Table.from_numpy(Domain.from_numpy(x_), x_) + + pca = PCA(10, svd_solver="full", random_state=random_state)(x) + rpca = PCA(10, svd_solver="randomized", random_state=random_state)(x) + + np.testing.assert_almost_equal( + pca.components_, rpca.components_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.explained_variance_, rpca.explained_variance_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.singular_values_, rpca.singular_values_, decimal=8 + ) + + def test_improved_randomized_pca_sparse_data(self): + """Randomized PCA should work well on dense data.""" + random_state = check_random_state(42) + + # Let's take a tall, skinny matrix + x_ = random_state.negative_binomial(1, 0.5, (100, 20)) + x = Table.from_numpy(Domain.from_numpy(x_), x_).to_sparse() + + pca = PCA(10, svd_solver="full", random_state=random_state)(x.to_dense()) + rpca = PCA(10, svd_solver="randomized", random_state=random_state)(x) + + np.testing.assert_almost_equal( + pca.components_, rpca.components_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.explained_variance_, rpca.explained_variance_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.singular_values_, rpca.singular_values_, decimal=8 + ) + + # And take a short, fat matrix + x_ = random_state.negative_binomial(1, 0.5, (20, 100)) + x = Table.from_numpy(Domain.from_numpy(x_), x_).to_sparse() + + pca = PCA(10, svd_solver="full", random_state=random_state)(x.to_dense()) + rpca = PCA(10, svd_solver="randomized", random_state=random_state)(x) + + np.testing.assert_almost_equal( + pca.components_, rpca.components_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.explained_variance_, rpca.explained_variance_, decimal=8 + ) + np.testing.assert_almost_equal( + pca.singular_values_, rpca.singular_values_, decimal=8 + ) + + @unittest.skipIf(sklearn_version.startswith('0.20'), + "https://github.com/scikit-learn/scikit-learn/issues/12234") + def test_incremental_pca(self): + data = self.ionosphere + self.__ipca_test_helper(data, n_com=3, min_xpl_var=0.49) + self.__ipca_test_helper(data, n_com=32, min_xpl_var=1) + + def __ipca_test_helper(self, data, n_com, min_xpl_var): + pca = IncrementalPCA(n_components=n_com) + pca_model = pca(data[::2]) + pca_xpl_var = np.sum(pca_model.explained_variance_ratio_) + self.assertGreaterEqual(pca_xpl_var + 1e-6, min_xpl_var) + self.assertEqual(n_com, pca_model.n_components) + self.assertEqual((n_com, data.X.shape[1]), pca_model.components_.shape) + proj = np.dot(data.X - pca_model.mean_, pca_model.components_.T) + np.testing.assert_almost_equal(pca_model(data).X, proj) + pc1_ipca = pca_model.components_[0] + self.assertAlmostEqual(np.linalg.norm(pc1_ipca), 1) + pc1_pca = PCA(n_components=n_com)(data).components_[0] + self.assertAlmostEqual(np.linalg.norm(pc1_pca), 1) + self.assertNotAlmostEqual(abs(pc1_ipca.dot(pc1_pca)), 1, 2) + pc1_ipca = pca_model.partial_fit(data[1::2]).components_[0] + self.assertAlmostEqual(abs(pc1_ipca.dot(pc1_pca)), 1, 4) + + def test_truncated_svd(self): + data = self.ionosphere + self.__truncated_svd_test_helper(data, n_components=3, min_variance=0.5) + self.__truncated_svd_test_helper(data, n_components=10, min_variance=0.7) + self.__truncated_svd_test_helper(data, n_components=31, min_variance=0.99) + + def __truncated_svd_test_helper(self, data, n_components, min_variance): + model = TruncatedSVD(n_components=n_components)(data) + svd_variance = np.sum(model.explained_variance_ratio_) + self.assertGreaterEqual(svd_variance + 1e-6, min_variance) + self.assertEqual(n_components, model.n_components) + self.assertEqual((n_components, data.X.shape[1]), model.components_.shape) + proj = np.dot(data.X, model.components_.T) + np.testing.assert_almost_equal(model(data).X, proj) + + def test_compute_value(self): + iris = self.iris + pca = PCA(n_components=2)(iris) + pca_iris = pca(iris) + pca_iris2 = iris.transform(pca_iris.domain) + np.testing.assert_almost_equal(pca_iris.X, pca_iris2.X) + np.testing.assert_equal(pca_iris.Y, pca_iris2.Y) + + pca_iris3 = pickle.loads(pickle.dumps(pca_iris)) + np.testing.assert_almost_equal(pca_iris.X, pca_iris3.X) + np.testing.assert_equal(pca_iris.Y, pca_iris3.Y) + + def test_transformed_domain_does_not_pickle_data(self): + iris = self.iris + pca = PCA(n_components=2)(iris) + pca_iris = pca(iris) + pca_iris2 = iris.transform(pca_iris.domain) + + pca_iris2 = pickle.loads(pickle.dumps(pca_iris)) + self.assertIsNone(pca_iris2.domain[0].compute_value.transformed) + + def test_chain(self): + zoo_c = Continuize()(self.zoo) + pca = PCA(n_components=3)(zoo_c)(self.zoo) + pca2 = PCA(n_components=3)(zoo_c)(zoo_c) + pp = [Continuize()] + pca3 = PCA(n_components=3, preprocessors=pp)(self.zoo)(self.zoo) + np.testing.assert_almost_equal(pca.X, pca2.X) + np.testing.assert_almost_equal(pca.X, pca3.X) + + def test_PCA_scorer(self): + data = self.iris + pca = PCA(preprocessors=[Normalize()]) + pca.component = 1 + scores = pca.score_data(data) + self.assertEqual(scores.shape[1], len(data.domain.attributes)) + self.assertEqual(['petal length', 'petal width'], + sorted([data.domain.attributes[i].name + for i in np.argsort(scores[0])[-2:]])) + self.assertEqual([round(s, 4) for s in scores[0]], + [0.5224, 0.2634, 0.5813, 0.5656]) + + def test_PCA_scorer_component(self): + pca = PCA() + for i in range(1, len(self.zoo.domain.attributes) + 1): + pca.component = i + scores = pca.score_data(self.zoo) + self.assertEqual(scores.shape, + (pca.component, len(self.zoo.domain.attributes))) + + def test_PCA_scorer_all_components(self): + n_attr = len(self.iris.domain.attributes) + pca = PCA() + scores = pca.score_data(self.iris) + self.assertEqual(scores.shape, (n_attr, n_attr)) + + def test_max_components(self): + d = np.random.RandomState(0).rand(20, 20) + data = Table.from_numpy(None, d) + pca = PCA()(data) + self.assertEqual(len(pca.explained_variance_ratio_), 20) + pca = PCA(n_components=10)(data) + self.assertEqual(len(pca.explained_variance_ratio_), 10) diff --git a/pyminer2/tests/test_polynomial_learner.py b/pyminer2/tests/test_polynomial_learner.py new file mode 100644 index 0000000000000000000000000000000000000000..af5296a2eaf59ff8bd376606ea9bead13e1f7e3f --- /dev/null +++ b/pyminer2/tests/test_polynomial_learner.py @@ -0,0 +1,29 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np + +from Orange.data import Table, ContinuousVariable, Domain +from Orange.regression import LinearRegressionLearner, PolynomialLearner +from Orange.evaluation import TestOnTrainingData, RMSE + +class TestPolynomialLearner(unittest.TestCase): + def test_PolynomialLearner(self): + x = np.array([0.172, 0.167, 0.337, 0.420, 0.355, 0.710, 0.801, 0.876]) + y = np.array([0.784, 0.746, 0.345, 0.363, 0.366, 0.833, 0.490, 0.445]) + + data = Table.from_numpy(None, x.reshape(-1, 1), y) + data.domain = Domain([ContinuousVariable('x')], + class_vars=[ContinuousVariable('y')]) + + linear = LinearRegressionLearner() + polynomial2 = PolynomialLearner(linear, degree=2) + polynomial3 = PolynomialLearner(linear, degree=3) + + tt = TestOnTrainingData() + res = tt(data, [linear, polynomial2, polynomial3]) + rmse = RMSE(res) + + self.assertGreater(rmse[0], rmse[1]) + self.assertGreater(rmse[1], rmse[2]) diff --git a/pyminer2/tests/test_preprocess.py b/pyminer2/tests/test_preprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..c588cdd710240bb59bddfaa66d0aa986931d1a2f --- /dev/null +++ b/pyminer2/tests/test_preprocess.py @@ -0,0 +1,203 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import os +import pickle +import unittest +from unittest.mock import Mock + +import numpy as np +from scipy.sparse import csr_matrix + +from Orange.data import Table, Domain, ContinuousVariable +from Orange.preprocess import EntropyMDL, DoNotImpute, Default, Average, \ + SelectRandomFeatures, EqualFreq, RemoveNaNColumns, DropInstances, \ + EqualWidth, SelectBestFeatures, RemoveNaNRows, Preprocess, Scale, \ + Randomize, Continuize, Discretize, Impute, SklImpute, Normalize, \ + ProjectCUR, ProjectPCA, RemoveConstant, AdaptiveNormalize, RemoveSparse +from Orange.util import OrangeDeprecationWarning + + +class TestPreprocess(unittest.TestCase): + def test_read_data_calls_reader(self): + class MockPreprocessor(Preprocess): + __init__ = Mock(return_value=None) + __call__ = Mock() + @classmethod + def reset(cls): + cls.__init__.reset_mock() + cls.__call__.reset_mock() + + table = Mock(Table) + MockPreprocessor(1, 2, a=3)(table) + MockPreprocessor.__init__.assert_called_with(1, 2, a=3) + MockPreprocessor.__call__.assert_called_with(table) + MockPreprocessor.reset() + + MockPreprocessor(1, 2, a=3) + MockPreprocessor.__init__.assert_called_with(1, 2, a=3) + self.assertEqual(MockPreprocessor.__call__.call_count, 0) + + MockPreprocessor(a=3) + MockPreprocessor.__init__.assert_called_with(a=3) + self.assertEqual(MockPreprocessor.__call__.call_count, 0) + + MockPreprocessor() + MockPreprocessor.__init__.assert_called_with() + self.assertEqual(MockPreprocessor.__call__.call_count, 0) + + +class TestRemoveConstant(unittest.TestCase): + def test_remove_columns(self): + X = np.random.rand(6, 5) + X[:, (1, 3)] = 5 + X[3, 1] = np.nan + X[1, 1] = np.nan + X[:, 4] = np.nan + data = Table.from_numpy(None, X) + d = RemoveConstant()(data) + self.assertEqual(len(d.domain.attributes), 2) + + pp_rc = RemoveConstant() + d = pp_rc(data) + self.assertEqual(len(d.domain.attributes), 2) + + def test_nothing_to_remove(self): + data = Table("iris") + d = RemoveConstant()(data) + self.assertEqual(len(d.domain.attributes), 4) + + +class TestRemoveNaNRows(unittest.TestCase): + def test_remove_row(self): + data = Table("iris") + data.X[0, 0] = np.nan + pp_data = RemoveNaNRows()(data) + self.assertEqual(len(pp_data), len(data) - 1) + self.assertFalse(np.isnan(pp_data.X).any()) + + +class TestRemoveNaNColumns(unittest.TestCase): + def test_column_filtering(self): + data = Table("iris") + data.X[:, (1, 3)] = np.NaN + + new_data = RemoveNaNColumns()(data) + self.assertEqual(len(new_data.domain.attributes), + len(data.domain.attributes) - 2) + + data = Table("iris") + data.X[0, 0] = np.NaN + new_data = RemoveNaNColumns()(data) + self.assertEqual(len(new_data.domain.attributes), + len(data.domain.attributes)) + + def test_column_filtering_sparse(self): + data = Table("iris") + data.X = csr_matrix(data.X) + + new_data = RemoveNaNColumns()(data) + self.assertEqual(data, new_data) + + +class TestScaling(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.table = Table.from_numpy(None, [[1, 2, 3], + [2, 3, 4], + [3, 4, 5], + [4, 5, 6]]) + + def test_scaling_mean_span(self): + table = Scale(center=Scale.Mean, scale=Scale.Span)(self.table) + np.testing.assert_almost_equal(np.mean(table, 0), 0) + np.testing.assert_almost_equal(np.ptp(table, 0), 1) + + def test_scaling_median_stddev(self): + table = Scale(center=Scale.Median, scale=Scale.Std)(self.table) + np.testing.assert_almost_equal(np.std(table, 0), 1) + # NB: This test just covers. The following fails. You figure it out. + # np.testing.assert_almost_equal(np.median(table, 0), 0) + + +class TestReprs(unittest.TestCase): + def test_reprs(self): + preprocs = [Continuize, Discretize, Impute, SklImpute, Normalize, + Randomize, ProjectPCA, ProjectCUR, Scale, + EqualFreq, EqualWidth, EntropyMDL, SelectBestFeatures, + SelectRandomFeatures, RemoveNaNColumns, DoNotImpute, DropInstances, + Average, Default, RemoveSparse] + + for preproc in preprocs: + repr_str = repr(preproc()) + new_preproc = eval(repr_str) + self.assertEqual(repr(new_preproc), repr_str) + + +class TestEnumPickling(unittest.TestCase): + def test_continuize_pickling(self): + c = Continuize(multinomial_treatment=Continuize.FirstAsBase) + s = pickle.dumps(c, -1) + c1 = pickle.loads(s) + self.assertIs(c1.multinomial_treatment, c.multinomial_treatment) + + def test_randomize_pickling(self): + c = Randomize(rand_type=Randomize.RandomizeMetas) + s = pickle.dumps(c, -1) + c1 = pickle.loads(s) + self.assertIs(c1.rand_type, c.rand_type) + + def test_scaling_pickling(self): + c = Scale(center=Scale.Median, scale=Scale.Span) + s = pickle.dumps(c, -1) + c1 = pickle.loads(s) + self.assertIs(c1.center, c.center) + self.assertIs(c1.scale, c.scale) + + +class TestAdaptiveNormalize(unittest.TestCase): + """ + Checks if output for sparse data is the same as for Scale + preprocessor. For dense data the output should match that + of Normalize preprocessor. + """ + + def setUp(self): + self.data = Table("iris") + + def test_dense_pps(self): + true_out = Normalize()(self.data) + out = AdaptiveNormalize()(self.data) + np.testing.assert_array_equal(out, true_out) + + def test_sparse_pps(self): + self.data.X = csr_matrix(self.data.X) + out = AdaptiveNormalize()(self.data) + true_out = Scale(center=Scale.NoCentering, scale=Scale.Span)(self.data) + np.testing.assert_array_equal(out, true_out) + self.data = self.data.X.toarray() + + +class TestRemoveSparse(unittest.TestCase): + + def setUp(self): + domain = Domain([ContinuousVariable('a'), ContinuousVariable('b')]) + self.data = Table.from_numpy(domain, np.zeros((3, 2))) + self.data[1:, 1] = 7 + + def test_dense(self): + true_out = self.data[:, 1] + true_out.X = true_out.X.reshape(-1, 1) + out = RemoveSparse(0.5)(self.data) + np.testing.assert_array_equal(out, true_out) + + def test_sparse(self): + true_out = self.data[:, 1] + self.data.X = csr_matrix(self.data.X) + true_out.X = csr_matrix(true_out.X) + out = RemoveSparse(0.5)(self.data).X + np.testing.assert_array_equal(out, true_out) + + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/test_preprocess_cur.py b/pyminer2/tests/test_preprocess_cur.py new file mode 100644 index 0000000000000000000000000000000000000000..22a6bd76635b4c4efe036a91c7eb2794815adc16 --- /dev/null +++ b/pyminer2/tests/test_preprocess_cur.py @@ -0,0 +1,36 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table +from Orange.preprocess import ProjectCUR +from Orange.tests import test_filename + + +class TestCURProjector(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.ionosphere = Table(test_filename("datasets/ionosphere.tab")) + + def test_project_cur_default(self): + data = self.ionosphere + projector = ProjectCUR() + data_cur = projector(data) + for i in range(data_cur.X.shape[1]): + sbtr = (data.X - data_cur.X[:, i][:, None]) == 0 + self.assertTrue(((sbtr.sum(0) == data.X.shape[0])).any()) + self.assertTrue(data_cur.X.shape[1] <= data.X.shape[1]) + self.assertTrue((data.metas == data_cur.metas).all()) + self.assertTrue((data.Y == data_cur.Y).any()) + + def test_project_cur(self): + data = self.ionosphere + projector = ProjectCUR(rank=3, max_error=1) + data_cur = projector(data) + for i in range(data_cur.X.shape[1]): + sbtr = (data.X - data_cur.X[:, i][:, None]) == 0 + self.assertTrue(((sbtr.sum(0) == data.X.shape[0])).any()) + self.assertTrue(data_cur.X.shape[1] <= data.X.shape[1]) + self.assertTrue((data.metas == data_cur.metas).all()) + self.assertTrue((data.Y == data_cur.Y).any()) diff --git a/pyminer2/tests/test_preprocess_pca.py b/pyminer2/tests/test_preprocess_pca.py new file mode 100644 index 0000000000000000000000000000000000000000..e57e52cdea672389a1896466a3129878654f269a --- /dev/null +++ b/pyminer2/tests/test_preprocess_pca.py @@ -0,0 +1,30 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table +from Orange.preprocess import ProjectPCA +from Orange.tests import test_filename + + +class TestPCAProjector(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.ionosphere = Table(test_filename("datasets/ionosphere.tab")) + + def test_project_pca_default(self): + data = self.ionosphere + projector = ProjectPCA() + data_pc = projector(data) + self.assertEqual(data_pc.X.shape[1], data.X.shape[1]) + self.assertTrue((data.metas == data_pc.metas).all()) + self.assertTrue((data.Y == data_pc.Y).any()) + + def test_project_pca(self): + data = self.ionosphere + projector = ProjectPCA(n_components=5) + data_pc = projector(data) + self.assertEqual(data_pc.X.shape[1], 5) + self.assertTrue((data.metas == data_pc.metas).all()) + self.assertTrue((data.Y == data_pc.Y).any()) diff --git a/pyminer2/tests/test_radviz.py b/pyminer2/tests/test_radviz.py new file mode 100644 index 0000000000000000000000000000000000000000..27e817f9ee65f2a885f7dc6505185c95f0cb0710 --- /dev/null +++ b/pyminer2/tests/test_radviz.py @@ -0,0 +1,36 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import unittest +import numpy as np + +from Orange.data import Table, Domain +from Orange.projection import RadViz + + +class TestRadViz(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table("iris") + cls.iris[3, 3] = np.nan + cls.titanic = Table("titanic") + + def test_radviz(self): + table = self.iris + table = table.transform(Domain(table.domain.attributes[2:])) + projector = RadViz() + projection = projector(table) + embedding = projection(table) + self.assertEqual(len(embedding), len(table)) + self.assertTrue(np.isnan(embedding.X).any()) + np.testing.assert_array_equal(embedding[:100], projection(table[:100])) + + def test_discrete_features(self): + table = self.titanic[::10] + projector = RadViz() + self.assertRaises(ValueError, projector, table) + + table = table.transform(Domain(table.domain.attributes[1:])) + projector = RadViz() + projection = projector(table) + embedding = projection(table[::10]) + self.assertEqual(np.sum(embedding), -17) diff --git a/pyminer2/tests/test_random_forest.py b/pyminer2/tests/test_random_forest.py new file mode 100644 index 0000000000000000000000000000000000000000..c5abda57b9701c360d526eeb9bdaff38266a12b1 --- /dev/null +++ b/pyminer2/tests/test_random_forest.py @@ -0,0 +1,113 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np +from Orange.data import Table +from Orange.evaluation import CrossValidation, CA, RMSE +from Orange.classification import RandomForestLearner +from Orange.regression import RandomForestRegressionLearner +from Orange.tests import test_filename + + +class RandomForestTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.housing = Table('housing') + + def test_RandomForest(self): + forest = RandomForestLearner() + cv = CrossValidation(k=10) + results = cv(self.iris, [forest]) + ca = CA(results) + self.assertGreater(ca, 0.9) + self.assertLess(ca, 0.99) + + def test_predict_single_instance(self): + forest = RandomForestLearner() + c = forest(self.iris) + for ins in self.iris: + c(ins) + val, prob = c(ins, c.ValueProbs) + + def test_predict_table(self): + forest = RandomForestLearner() + c = forest(self.iris) + c(self.iris) + vals, probs = c(self.iris, c.ValueProbs) + + def test_predict_numpy(self): + forest = RandomForestLearner() + c = forest(self.iris) + c(self.iris.X) + vals, probs = c(self.iris.X, c.ValueProbs) + + def test_RandomForestRegression(self): + forest = RandomForestRegressionLearner() + cv = CrossValidation(k=10) + results = cv(self.housing, [forest]) + _ = RMSE(results) + + def test_predict_single_instance_reg(self): + forest = RandomForestRegressionLearner() + model = forest(self.housing) + for ins in self.housing: + pred = model(ins) + self.assertGreater(pred, 0) + + def test_predict_table_reg(self): + forest = RandomForestRegressionLearner() + model = forest(self.housing) + pred = model(self.housing) + self.assertEqual(len(self.housing), len(pred)) + self.assertGreater(all(pred), 0) + + def test_predict_numpy_reg(self): + forest = RandomForestRegressionLearner() + model = forest(self.housing) + pred = model(self.housing.X) + self.assertEqual(len(self.housing), len(pred)) + self.assertGreater(all(pred), 0) + + def test_classification_scorer(self): + learner = RandomForestLearner() + scores = learner.score_data(self.iris) + self.assertEqual(scores.shape[1], len(self.iris.domain.attributes)) + self.assertNotEqual(sum(scores[0]), 0) + self.assertEqual(['petal length', 'petal width'], + sorted([self.iris.domain.attributes[i].name + for i in np.argsort(scores[0])[-2:]])) + + def test_regression_scorer(self): + learner = RandomForestRegressionLearner() + scores = learner.score_data(self.housing) + self.assertEqual(['LSTAT', 'RM'], + sorted([self.housing.domain.attributes[i].name + for i in np.argsort(scores[0])[-2:]])) + + def test_scorer_feature(self): + np.random.seed(42) + data = Table(test_filename('datasets/test4.tab')) + learner = RandomForestLearner() + scores = learner.score_data(data) + for i, attr in enumerate(data.domain.attributes): + np.random.seed(42) + score = learner.score_data(data, attr) + np.testing.assert_array_almost_equal(score, scores[:, i]) + + def test_get_classification_trees(self): + n = 5 + forest = RandomForestLearner(n_estimators=n) + model = forest(self.iris) + self.assertEqual(len(model.trees), n) + tree = model.trees[0] + self.assertEqual(tree(self.iris[0]), 0) + + def test_get_regression_trees(self): + n = 5 + forest = RandomForestRegressionLearner(n_estimators=n) + model = forest(self.housing) + self.assertEqual(len(model.trees), n) + tree = model.trees[0] + tree(self.housing[0]) diff --git a/pyminer2/tests/test_randomize.py b/pyminer2/tests/test_randomize.py new file mode 100644 index 0000000000000000000000000000000000000000..97048e3cf995e92d4cedbe3d33a2a54f4d0c486b --- /dev/null +++ b/pyminer2/tests/test_randomize.py @@ -0,0 +1,135 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np +import scipy.sparse as sp +from Orange.data import Table +from Orange.preprocess import Randomize + + +class TestRandomizer(unittest.TestCase): + @classmethod + def setUpClass(cls): + np.random.seed(42) + cls.zoo = Table("zoo") + + def test_randomize_default(self): + data = self.zoo + randomizer = Randomize() + data_rand = randomizer(data) + self.assertTrue((data.X == data_rand.X).all()) + self.assertTrue((data.metas == data_rand.metas).all()) + self.assertTrue((data.Y != data_rand.Y).any()) + self.assertTrue((np.sort(data.Y, axis=0) == np.sort( + data_rand.Y, axis=0)).all()) + + def test_randomize_classes(self): + data = self.zoo + randomizer = Randomize(rand_type=Randomize.RandomizeClasses) + data_rand = randomizer(data) + self.assertTrue((data.X == data_rand.X).all()) + self.assertTrue((data.metas == data_rand.metas).all()) + self.assertTrue((data.Y != data_rand.Y).any()) + self.assertTrue((np.sort(data.Y, axis=0) == np.sort( + data_rand.Y, axis=0)).all()) + + def test_randomize_attributes(self): + data = self.zoo + randomizer = Randomize(rand_type=Randomize.RandomizeAttributes) + data_rand = randomizer(data) + self.assertTrue((data.Y == data_rand.Y).all()) + self.assertTrue((data.metas == data_rand.metas).all()) + self.assertTrue((data.X != data_rand.X).any()) + self.assertTrue((np.sort(data.X, axis=0) == np.sort( + data_rand.X, axis=0)).all()) + + def test_randomize_metas(self): + data = self.zoo + randomizer = Randomize(rand_type=Randomize.RandomizeMetas) + data_rand = randomizer(data) + self.assertTrue((data.X == data_rand.X).all()) + self.assertTrue((data.Y == data_rand.Y).all()) + self.assertTrue((data.metas != data_rand.metas).any()) + self.assertTrue((np.sort(data.metas, axis=0) == np.sort( + data_rand.metas, axis=0)).all()) + + def test_randomize_all(self): + data = self.zoo + rand_type = Randomize.RandomizeClasses | Randomize.RandomizeAttributes \ + | Randomize.RandomizeMetas + randomizer = Randomize(rand_type=rand_type) + data_rand = randomizer(data) + self.assertTrue((data.Y != data_rand.Y).any()) + self.assertTrue((np.sort(data.Y, axis=0) == np.sort( + data_rand.Y, axis=0)).all()) + self.assertTrue((data.X != data_rand.X).any()) + self.assertTrue((np.sort(data.X, axis=0) == np.sort( + data_rand.X, axis=0)).all()) + self.assertTrue((data.metas != data_rand.metas).any()) + self.assertTrue((np.sort(data.metas, axis=0) == np.sort( + data_rand.metas, axis=0)).all()) + + def test_randomize_keep_original_data(self): + data_orig = self.zoo + data = Table("zoo") + _ = Randomize(rand_type=Randomize.RandomizeClasses)(data) + _ = Randomize(rand_type=Randomize.RandomizeAttributes)(data) + _ = Randomize(rand_type=Randomize.RandomizeMetas)(data) + self.assertTrue((data.X == data_orig.X).all()) + self.assertTrue((data.metas == data_orig.metas).all()) + self.assertTrue((data.Y == data_orig.Y).all()) + + def test_randomize_replicate(self): + randomizer1 = Randomize(rand_seed=1) + rand_data11 = randomizer1(self.zoo) + rand_data12 = randomizer1(self.zoo) + randomizer2 = Randomize(rand_seed=1) + rand_data2 = randomizer2(self.zoo) + np.testing.assert_array_equal(rand_data11.Y, rand_data12.Y) + np.testing.assert_array_equal(rand_data11.Y, rand_data2.Y) + + def test_randomize(self): + x = np.arange(10000, dtype=int).reshape((100, 100)) + randomized = Randomize().randomize(x.copy()) + + # Do not mix data between columns + np.testing.assert_equal(randomized % 100, x % 100) + + # Do not shuffle entire rows: + # lexical sorting of rows should not equal the original table + randomized = np.array(sorted(list(map(list, randomized))), dtype=int) + self.assertFalse(np.all(randomized == x)) + + def test_randomize_sparse(self): + x = np.array([[0, 0, 3, 0], + [1, 0, 2, 0], + [4, 5, 6, 7]]) + randomize = Randomize().randomize + + randomized = randomize(sp.csr_matrix(x), rand_state=1) + randomized = randomized.toarray() + # Data is shuffled (rand_seed=1 should always shuffle it) + self.assertFalse(np.all(x == randomized)) + # Data remains within a column + self.assertTrue(all(sorted(x[:, i]) == sorted(randomized[:, i]) + for i in range(4))) + # Do not shuffle entire rows + randomized = np.array(sorted(list(map(list, randomized))), dtype=int) + self.assertFalse(np.all(randomized == x)) + + # Test that shuffle is not sparse structure dependent + x = np.array([[1, 2, 3, 4], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + + randomized = randomize(sp.csr_matrix(x), rand_state=0x393f) + self.assertFalse(np.all(x == randomized.todense())) + + # Do not just assign some indices. I.e. make sure that the shuffling is + # dependent in the input's non-zero indices. + r_once = randomize(sp.csr_matrix(x), rand_state=1) + r_twice = randomize(r_once.copy(), rand_state=1) + self.assertFalse(np.all(r_once.todense() == r_twice.todense())) diff --git a/pyminer2/tests/test_regression.py b/pyminer2/tests/test_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..b562a341515cb5dbc8d338fafa73142a025b4fc5 --- /dev/null +++ b/pyminer2/tests/test_regression.py @@ -0,0 +1,60 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import inspect +import pkgutil +import traceback + +import Orange +from Orange.data import Table, Variable +from Orange.regression import Learner +from Orange.tests import test_filename + + +class TestRegression(unittest.TestCase): + def all_learners(self): + regression_modules = pkgutil.walk_packages( + path=Orange.regression.__path__, + prefix="Orange.regression.", + onerror=lambda x: None) + for importer, modname, ispkg in regression_modules: + try: + module = pkgutil.importlib.import_module(modname) + except ImportError: + continue + + for name, class_ in inspect.getmembers(module, inspect.isclass): + if issubclass(class_, Learner) and 'base' not in class_.__module__: + yield class_ + + def test_adequacy_all_learners(self): + for learner in self.all_learners(): + try: + learner = learner() + table = Table("iris") + self.assertRaises(ValueError, learner, table) + except TypeError as err: + traceback.print_exc() + continue + + def test_adequacy_all_learners_multiclass(self): + for learner in self.all_learners(): + try: + learner = learner() + table = Table(test_filename("datasets/test8.tab")) + self.assertRaises(ValueError, learner, table) + except TypeError as err: + traceback.print_exc() + continue + + def test_missing_class(self): + table = Table(test_filename("datasets/imports-85.tab")) + for learner in self.all_learners(): + try: + learner = learner() + model = learner(table) + model(table) + except TypeError: + traceback.print_exc() + continue diff --git a/pyminer2/tests/test_remove.py b/pyminer2/tests/test_remove.py new file mode 100644 index 0000000000000000000000000000000000000000..cf5ccc9dd42a8331b877e15f4a498bf28b7b5db0 --- /dev/null +++ b/pyminer2/tests/test_remove.py @@ -0,0 +1,162 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +import numpy as np + +from Orange.data import Table +from Orange.preprocess import Remove +from Orange.tests import test_filename + + +class TestRemover(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.test8 = Table(test_filename('datasets/test8.tab')) + + def test_remove(self): + data = Table("iris")[:5] + attr_flags = sum([Remove.SortValues, + Remove.RemoveConstant, + Remove.RemoveUnusedValues]) + class_flags = sum([Remove.SortValues, + Remove.RemoveConstant, + Remove.RemoveUnusedValues]) + remover = Remove(attr_flags, class_flags) + new_data = remover(data) + attr_res, class_res = remover.attr_results, remover.class_results + + self.assertEqual([a.name for a in new_data.domain.attributes], + ["sepal length", "sepal width", "petal length"]) + self.assertEqual([c.name for c in new_data.domain.class_vars], []) + self.assertDictEqual(attr_res, + {'removed': 1, 'reduced': 0, 'sorted': 0}) + self.assertDictEqual(class_res, + {'removed': 1, 'reduced': 0, 'sorted': 0}) + + def test_remove_constant_attr(self): + data = self.test8 + remover = Remove(Remove.RemoveConstant) + new_data = remover(data) + attr_res, class_res = remover.attr_results, remover.class_results + + np.testing.assert_equal(new_data.X, np.hstack((data[:, 1], + data[:, 3]))) + np.testing.assert_equal(new_data.Y, data.Y) + self.assertEqual([a.name for a in new_data.domain.attributes], + ["c0", "d0"]) + self.assertEqual([c.name for c in new_data.domain.class_vars], + ["cl1", "cl0", "cl3", "cl4"]) + self.assertEqual([a.values for a in new_data.domain.attributes + if a.is_discrete], [['4', '6']]) + self.assertEqual([c.values for c in new_data.domain.class_vars + if c.is_discrete], [['1', '2', '3'], ['2']]) + self.assertDictEqual(attr_res, + {'removed': 2, 'reduced': 0, 'sorted': 0}) + self.assertDictEqual(class_res, + {'removed': 0, 'reduced': 0, 'sorted': 0}) + + def test_remove_constant_class(self): + data = self.test8 + remover = Remove(class_flags=Remove.RemoveConstant) + new_data = remover(data) + attr_res, class_res = remover.attr_results, remover.class_results + + np.testing.assert_equal(new_data.X, data.X) + np.testing.assert_equal(new_data.Y, np.hstack((data[:, 4], + data[:, 5]))) + self.assertEqual([a.name for a in new_data.domain.attributes], + ["c1", "c0", "d1", "d0"]) + self.assertEqual([c.name for c in new_data.domain.class_vars], + ["cl1", "cl0"]) + self.assertEqual([a.values for a in new_data.domain.attributes + if a.is_discrete], [['1'], ['4', '6']]) + self.assertEqual([c.values for c in new_data.domain.class_vars + if c.is_discrete], [['1', '2', '3']]) + self.assertDictEqual(attr_res, + {'removed': 0, 'reduced': 0, 'sorted': 0}) + self.assertDictEqual(class_res, + {'removed': 2, 'reduced': 0, 'sorted': 0}) + + def test_remove_unused_values_attr(self): + data = self.test8 + data = data[1:] + remover = Remove(Remove.RemoveUnusedValues) + new_data = remover(data) + attr_res, class_res = remover.attr_results, remover.class_results + + np.testing.assert_equal(new_data.X, data.X) + np.testing.assert_equal(new_data.Y, data.Y) + self.assertEqual([a.name for a in new_data.domain.attributes], + ["c1", "c0", "d1", "d0"]) + self.assertEqual([c.name for c in new_data.domain.class_vars], + ["cl1", "cl0", "cl3", "cl4"]) + self.assertEqual([a.values for a in new_data.domain.attributes + if a.is_discrete], [['1'], ['4']]) + self.assertEqual([c.values for c in new_data.domain.class_vars + if c.is_discrete], [['1', '2', '3'], ['2']]) + self.assertDictEqual(attr_res, + {'removed': 0, 'reduced': 1, 'sorted': 0}) + self.assertDictEqual(class_res, + {'removed': 0, 'reduced': 0, 'sorted': 0}) + + def test_remove_unused_values_class(self): + data = self.test8 + data = data[:2] + remover = Remove(class_flags=Remove.RemoveUnusedValues) + new_data = remover(data) + attr_res, class_res = remover.attr_results, remover.class_results + + for i in range(len(data)): + for j in range(len(data[i])): + self.assertEqual(new_data[i, j], data[i, j]) + + self.assertEqual([a.name for a in new_data.domain.attributes], + ["c1", "c0", "d1", "d0"]) + self.assertEqual([c.name for c in new_data.domain.class_vars], + ["cl1", "cl0", "cl3", "cl4"]) + self.assertEqual([a.values for a in new_data.domain.attributes + if a.is_discrete], [['1'], ['4', '6']]) + self.assertEqual([c.values for c in new_data.domain.class_vars + if c.is_discrete], [['2', '3'], ['2']]) + self.assertDictEqual(attr_res, + {'removed': 0, 'reduced': 0, 'sorted': 0}) + self.assertDictEqual(class_res, + {'removed': 0, 'reduced': 1, 'sorted': 0}) + + def test_remove_unused_values_metas(self): + data = Table(test_filename("datasets/test9.tab")) + subset = data[:4] + res = Remove(attr_flags=Remove.RemoveUnusedValues, + meta_flags=Remove.RemoveUnusedValues)(subset) + + self.assertEqual(res.domain["b"].values, res.domain["c"].values) + self.assertEqual(res.domain["d"].values, ["1", "2"]) + self.assertEqual(res.domain["f"].values, ['1', 'hey']) + + def test_remove_unused_values_attr_sparse(self): + data = self.test8 + data = data[1:].to_sparse() + remover = Remove(Remove.RemoveUnusedValues) + new_data = remover(data) + attr_res = remover.attr_results + + self.assertEqual((new_data.X != data.X).nnz, 0) + self.assertEqual([a.values for a in new_data.domain.attributes + if a.is_discrete], [['1'], ['4']]) + self.assertEqual([c.values for c in new_data.domain.class_vars + if c.is_discrete], [['1', '2', '3'], ['2']]) + self.assertDictEqual(attr_res, + {'removed': 0, 'reduced': 1, 'sorted': 0}) + + def test_remove_mapping(self): + data = Table("iris") + x = np.vstack((data.X[:50], data.X[100:])) + y = np.hstack((data.Y[:50], data.Y[100:])) + data = Table.from_numpy(data.domain, x, y) + remover = Remove(class_flags=Remove.RemoveUnusedValues) + cleaned = remover(data) + np.testing.assert_array_equal(cleaned.Y[:50], 0) + np.testing.assert_array_equal(cleaned.Y[50:], 1) diff --git a/pyminer2/tests/test_rules.py b/pyminer2/tests/test_rules.py new file mode 100644 index 0000000000000000000000000000000000000000..ea86494d5cfec6f3da0db054a154ea879edde552 --- /dev/null +++ b/pyminer2/tests/test_rules.py @@ -0,0 +1,209 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np + +from Orange.classification import (CN2Learner, CN2UnorderedLearner, + CN2SDLearner, CN2SDUnorderedLearner) +from Orange.classification.rules import (_RuleLearner, _RuleClassifier, + RuleHunter, Rule, EntropyEvaluator, + LaplaceAccuracyEvaluator, + WeightedRelativeAccuracyEvaluator, + argmaxrnd, hash_dist) +from Orange.data import Table +from Orange.data.filter import HasClass +from Orange.preprocess import Impute + + +class TestRuleInduction(unittest.TestCase): + + def setUp(self): + self.titanic = Table('titanic') + self.iris = Table('iris') + + def test_base_RuleLearner(self): + """ + Base rule induction learner test. To pass the test, all base + components are checked, including preprocessors, top-level + control procedure elements (covering algorithm, rule stopping, + data stopping), and bottom-level search procedure controller + (rule finder). + + Every learner that extends _RuleLearner should override the fit + method. It should at this point not yet be available (exception + raised). + """ + base_rule_learner = _RuleLearner() + + # test the number of default preprocessors + self.assertEqual(len(list(base_rule_learner.active_preprocessors)), 3) + # preprocessor types + preprocessor_types = [type(x) for x in base_rule_learner.active_preprocessors] + self.assertIn(HasClass, preprocessor_types) + self.assertIn(Impute, preprocessor_types) + + # test find_rules + base_rule_learner.domain = self.iris.domain + base_rule_learner.find_rules(self.iris.X, self.iris.Y.astype(int), + None, None, [], self.iris.domain) + + # test top-level control procedure elements + self.assertTrue(hasattr(base_rule_learner, "data_stopping")) + self.assertTrue(hasattr(base_rule_learner, "cover_and_remove")) + self.assertTrue(hasattr(base_rule_learner, "rule_stopping")) + + # test exclusive covering algorithm + new_rule = Rule() + new_rule.covered_examples = np.array([True, False, True], dtype=bool) + new_rule.target_class = None + + X, Y, W = base_rule_learner.exclusive_cover_and_remove( + self.iris.X[:3], self.iris.Y[:3], None, new_rule) + self.assertTrue(len(X) == len(Y) == 1) + + # test rule finder + self.assertTrue(hasattr(base_rule_learner, "rule_finder")) + rule_finder = base_rule_learner.rule_finder + self.assertIsInstance(rule_finder, RuleHunter) + self.assertTrue(hasattr(rule_finder, "search_algorithm")) + self.assertTrue(hasattr(rule_finder, "search_strategy")) + self.assertTrue(hasattr(rule_finder, "quality_evaluator")) + self.assertTrue(hasattr(rule_finder, "complexity_evaluator")) + self.assertTrue(hasattr(rule_finder, "general_validator")) + self.assertTrue(hasattr(rule_finder, "significance_validator")) + + def testBaseRuleClassifier(self): + """ + Every classifier that extends _RuleClassifier should override + the predict method. It should at this point not yet be available + (exception raised). + """ + base_rule_classifier = _RuleClassifier(domain=self.iris.domain) + self.assertRaises(NotImplementedError, base_rule_classifier.predict, + self.iris.X) + + def testCN2Learner(self): + learner = CN2Learner() + + # classic CN2 removes covered learning instances + self.assertTrue(learner.cover_and_remove == + _RuleLearner.exclusive_cover_and_remove) + + # Entropy measure is used to evaluate found hypotheses + self.assertTrue(type(learner.rule_finder.quality_evaluator) == + EntropyEvaluator) + + # test that the learning requirements are relaxed by default + self.assertTrue(learner.rule_finder.general_validator.max_rule_length >= 5) + self.assertTrue(learner.rule_finder.general_validator.min_covered_examples == 1) + + classifier = learner(self.titanic) + self.assertEqual(classifier.original_domain, self.titanic.domain) + + # all learning instances are covered when limitations do not + # impose rule length or minimum number of covered examples + num_covered = np.sum([rule.curr_class_dist + for rule in classifier.rule_list[:-1]]) + self.assertEqual(num_covered, self.titanic.X.shape[0]) + + # prediction (matrix-wise, all testing instances at once) + # test that returned result is of correct size + predictions = classifier.predict(self.titanic.X) + self.assertEqual(len(predictions), self.titanic.X.shape[0]) + + def testUnorderedCN2Learner(self): + learner = CN2UnorderedLearner() + + # unordered CN2 removes covered learning instances + self.assertTrue(learner.cover_and_remove == + _RuleLearner.exclusive_cover_and_remove) + + # Laplace accuracy measure is used to evaluate found hypotheses + self.assertTrue(type(learner.rule_finder.quality_evaluator) == + LaplaceAccuracyEvaluator) + + # test that the learning requirements are relaxed by default + self.assertTrue(learner.rule_finder.general_validator.max_rule_length >= 5) + self.assertTrue(learner.rule_finder.general_validator.min_covered_examples == 1) + + # by default, continuous variables are + # constrained by the learning algorithm + self.assertTrue(learner.rule_finder.search_strategy.constrain_continuous) + + classifier = learner(self.iris) + self.assertEqual(classifier.original_domain, self.iris.domain) + + # all learning instances should be covered given the parameters + for curr_class in range(len(self.iris.domain.class_var.values)): + target_covered = (np.sum([rule.curr_class_dist[rule.target_class] + for rule in classifier.rule_list + if rule.target_class == curr_class])) + self.assertEqual(target_covered, np.sum(self.iris.Y == curr_class)) + + # a custom example, test setting several parameters + learner = CN2UnorderedLearner() + learner.rule_finder.search_algorithm.beam_width = 5 + learner.rule_finder.search_strategy.constrain_continuous = True + learner.rule_finder.general_validator.min_covered_examples = 10 + learner.rule_finder.general_validator.max_rule_length = 2 + learner.rule_finder.significance_validator.parent_alpha = 0.9 + learner.rule_finder.significance_validator.default_alpha = 0.8 + + classifier = learner(self.iris) + + # only the TRUE rule may exceed imposed limitations + for rule in classifier.rule_list[:-1]: + self.assertLessEqual(len(rule.selectors), 2) + self.assertGreaterEqual(np.max(rule.curr_class_dist), 10) + + # prediction (matrix-wise, all testing instances at once) + # test that returned result is of correct size + predictions = classifier.predict(self.iris.X) + self.assertEqual(len(predictions), self.iris.X.shape[0]) + + def testOrderedCN2SDLearner(self): + learner = CN2SDLearner() + + # Weighted relative accuracy measure is + # used to evaluate found hypotheses + self.assertTrue(type(learner.rule_finder.quality_evaluator) == + WeightedRelativeAccuracyEvaluator) + + # gamma parameter must be initialized and defined + self.assertTrue(hasattr(learner, "gamma")) + + classifier = learner(self.titanic) + self.assertEqual(classifier.original_domain, self.titanic.domain) + + # prediction (matrix-wise, all testing instances at once) + # test that returned result is of correct size + predictions = classifier.predict(self.titanic.X) + self.assertEqual(len(predictions), self.titanic.X.shape[0]) + + def testUnorderedCN2SDLearner(self): + learner = CN2SDUnorderedLearner() + learner.rule_finder.significance_validator.parent_alpha = 0.2 + learner.rule_finder.significance_validator.default_alpha = 0.8 + + self.assertTrue(type(learner.rule_finder.quality_evaluator) == + WeightedRelativeAccuracyEvaluator) + + # gamma parameter must be initialized and defined + self.assertTrue(hasattr(learner, "gamma")) + + classifier = learner(self.titanic) + self.assertEqual(classifier.original_domain, self.titanic.domain) + + # prediction (matrix-wise, all testing instances at once) + # test that returned result is of correct size + predictions = classifier.predict(self.titanic.X) + self.assertEqual(len(predictions), self.titanic.X.shape[0]) + + def testArgMaxRnd(self): + temp = np.array([np.nan, 1, 2.3, 37, 37, 37, 1]) + self.assertEqual(argmaxrnd(temp, hash_dist(np.array([3, 4]))), 5) + self.assertRaises(ValueError, argmaxrnd, np.ones((1, 1, 1))) + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/test_score_feature.py b/pyminer2/tests/test_score_feature.py new file mode 100644 index 0000000000000000000000000000000000000000..1e27c872e9a8b5a167d1966e2b8740313a1ec7d6 --- /dev/null +++ b/pyminer2/tests/test_score_feature.py @@ -0,0 +1,169 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import warnings + +import numpy as np + +from Orange.data import Table, Domain, DiscreteVariable, ContinuousVariable +from Orange import preprocess +from Orange.modelling import RandomForestLearner +from Orange.preprocess.score import InfoGain, GainRatio, Gini, Chi2, ANOVA,\ + UnivariateLinearRegression, ReliefF, FCBF, RReliefF +from Orange.projection import PCA +from Orange.tests import test_filename + + +class FeatureScoringTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.zoo = Table("zoo") # disc. features, disc. class + cls.housing = Table("housing") # cont. features, cont. class + cls.breast = Table(test_filename( + "datasets/breast-cancer-wisconsin.tab")) + cls.lenses = Table(test_filename("datasets/lenses.tab")) + + def test_info_gain(self): + scorer = InfoGain() + correct = [0.79067, 0.71795, 0.83014, 0.97432, 0.46970] + np.testing.assert_almost_equal([scorer(self.zoo, a) for a in range(5)], + correct, decimal=5) + + def test_gain_ratio(self): + scorer = GainRatio() + correct = [0.80351, 1.00000, 0.84754, 1.00000, 0.59376] + np.testing.assert_almost_equal([scorer(self.zoo, a) for a in range(5)], + correct, decimal=5) + + def test_gini(self): + scorer = Gini() + correct = [0.23786, 0.20855, 0.26235, 0.29300, 0.11946] + np.testing.assert_almost_equal([scorer(self.zoo, a) for a in range(5)], + correct, decimal=5) + + def test_classless(self): + classless = Table.from_table(Domain(self.zoo.domain.attributes), + self.zoo[:, 0:-1]) + scorers = [Gini(), InfoGain(), GainRatio()] + for scorer in scorers: + with self.assertRaises(ValueError): + scorer(classless, 0) + + def test_wrong_class_type(self): + scorers = [Gini(), InfoGain(), GainRatio()] + for scorer in scorers: + with self.assertRaises(ValueError): + scorer(self.housing, 0) + + with self.assertRaises(ValueError): + Chi2()(self.housing, 0) + with self.assertRaises(ValueError): + ANOVA()(self.housing, 2) + UnivariateLinearRegression()(self.housing, 2) + + def test_chi2(self): + nrows, ncols = 500, 5 + X = np.random.randint(4, size=(nrows, ncols)) + y = 10 + (-3*X[:, 1] + X[:, 3]) // 2 + domain = Domain.from_numpy(X, y) + domain = Domain(domain.attributes, + DiscreteVariable('c', + values=[str(v) for v in np.unique(y)])) + table = Table(domain, X, y) + data = preprocess.Discretize()(table) + scorer = Chi2() + sc = [scorer(data, a) for a in range(ncols)] + self.assertTrue(np.argmax(sc) == 1) + + def test_anova(self): + nrows, ncols = 500, 5 + X = np.random.rand(nrows, ncols) + y = 4 + (-3*X[:, 1] + X[:, 3]) // 2 + domain = Domain.from_numpy(X, y) + domain = Domain(domain.attributes, + DiscreteVariable('c', + values=[str(v) for v in np.unique(y)])) + data = Table(domain, X, y) + scorer = ANOVA() + sc = [scorer(data, a) for a in range(ncols)] + self.assertTrue(np.argmax(sc) == 1) + + def test_regression(self): + nrows, ncols = 500, 5 + X = np.random.rand(nrows, ncols) + y = (-3*X[:, 1] + X[:, 3]) / 2 + data = Table.from_numpy(None, X, y) + scorer = UnivariateLinearRegression() + sc = [scorer(data, a) for a in range(ncols)] + self.assertTrue(np.argmax(sc) == 1) + + def test_relieff(self): + old_breast = self.breast.copy() + weights = ReliefF(random_state=42)(self.breast, None) + found = [self.breast.domain[attr].name for attr in reversed(weights.argsort()[-3:])] + reference = ['Bare_Nuclei', 'Clump thickness', 'Marginal_Adhesion'] + self.assertEqual(sorted(found), reference) + # Original data is unchanged + np.testing.assert_equal(old_breast.X, self.breast.X) + np.testing.assert_equal(old_breast.Y, self.breast.Y) + # Ensure it doesn't crash on adult dataset + weights = ReliefF(random_state=42)(self.lenses, None) + found = [self.lenses.domain[attr].name for attr in weights.argsort()[-2:]] + # some leeway for randomness in relieff random instance selection + self.assertIn('tear_rate', found) + # Ensure it doesn't crash on missing target class values + old_breast.Y[0] = np.nan + weights = ReliefF()(old_breast, None) + + np.testing.assert_array_equal( + ReliefF(random_state=1)(self.breast, None), + ReliefF(random_state=1)(self.breast, None) + ) + + def test_rrelieff(self): + X = np.random.random((100, 5)) + y = ((X[:, 0] > .5) ^ (X[:, 1] < .5) - 1).astype(float) + xor = Table.from_numpy(Domain.from_numpy(X, y), X, y) + + scorer = RReliefF(random_state=42) + weights = scorer(xor, None) + best = {xor.domain[attr].name for attr in weights.argsort()[-2:]} + self.assertSetEqual(set(a.name for a in xor.domain.attributes[:2]), best) + weights = scorer(self.housing, None) + best = {self.housing.domain[attr].name for attr in weights.argsort()[-6:]} + for feature in ('LSTAT', 'RM'): + self.assertIn(feature, best) + + np.testing.assert_array_equal( + RReliefF(random_state=1)(self.housing, None), + RReliefF(random_state=1)(self.housing, None) + ) + + def test_fcbf(self): + scorer = FCBF() + weights = scorer(self.zoo, None) + found = [self.zoo.domain[attr].name for attr in reversed(weights.argsort()[-5:])] + reference = ['legs', 'milk', 'toothed', 'feathers', 'backbone'] + self.assertEqual(found, reference) + + # GH-1916 + data = Table(Domain([ContinuousVariable('1'), ContinuousVariable('2')], + DiscreteVariable('target')), + np.full((2, 2), np.nan), + np.r_[0., 1]) + with warnings.catch_warnings(): + # these warnings are expected + warnings.filterwarnings("ignore", "invalid value.*double_scalars") + warnings.filterwarnings("ignore", "invalid value.*true_divide") + + weights = scorer(data, None) + np.testing.assert_equal(weights, np.nan) + + def test_learner_with_transformation(self): + learner = RandomForestLearner(random_state=0) + iris = Table("iris") + data = PCA(n_components=2)(iris)(iris) + scores = learner.score_data(data) + np.testing.assert_almost_equal(scores, [[0.7760495, 0.2239505]]) diff --git a/pyminer2/tests/test_sgd.py b/pyminer2/tests/test_sgd.py new file mode 100644 index 0000000000000000000000000000000000000000..ebb1fe87b8d22ff30065f809aafe0507812e0bbc --- /dev/null +++ b/pyminer2/tests/test_sgd.py @@ -0,0 +1,57 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import warnings + +import numpy as np +from sklearn.exceptions import ConvergenceWarning + +from Orange.data import Table +from Orange.classification import SGDClassificationLearner +from Orange.regression import SGDRegressionLearner +from Orange.evaluation import CrossValidation, RMSE, AUC + + +class TestSGDRegressionLearner(unittest.TestCase): + def setUp(self): + # Convergence warnings are irrelevant for these tests + warnings.filterwarnings("ignore", ".*", ConvergenceWarning) + super().setUp() + + def test_SGDRegression(self): + nrows, ncols = 500, 5 + X = np.random.rand(nrows, ncols) + y = X.dot(np.random.rand(ncols)) + data = Table.from_numpy(None, X, y) + sgd = SGDRegressionLearner() + cv = CrossValidation(k=3) + res = cv(data, [sgd]) + self.assertLess(RMSE(res)[0], 0.1) + + def test_coefficients(self): + lrn = SGDRegressionLearner() + mod = lrn(Table("housing")) + self.assertEqual(len(mod.coefficients), len(mod.domain.attributes)) + + +class TestSGDClassificationLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + + def setUp(self): + # Convergence warnings are irrelevant for these tests + warnings.filterwarnings("ignore", ".*", ConvergenceWarning) + super().setUp() + + def test_SGDClassification(self): + sgd = SGDClassificationLearner() + cv = CrossValidation(k=3) + res = cv(self.iris, [sgd]) + self.assertGreater(AUC(res)[0], 0.8) + + def test_coefficients(self): + lrn = SGDClassificationLearner() + mod = lrn(self.iris) + self.assertEqual(len(mod.coefficients[0]), len(mod.domain.attributes)) diff --git a/pyminer2/tests/test_simple_random_forest.py b/pyminer2/tests/test_simple_random_forest.py new file mode 100644 index 0000000000000000000000000000000000000000..5e7f3a1f3b4939b96ce0e618b02a25fe702e0d2d --- /dev/null +++ b/pyminer2/tests/test_simple_random_forest.py @@ -0,0 +1,31 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import numpy as np +import Orange +from Orange.classification import SimpleRandomForestLearner as SimpRandForestCls +from Orange.regression import SimpleRandomForestLearner as SimpRandForestReg + + +class TestSimpleRandomForestLearner(unittest.TestCase): + def test_SimpleRandomForest_classification(self): + data = Orange.data.Table('iris') + lrn = SimpRandForestCls() + clf = lrn(data) + p = clf(data, clf.Probs) + self.assertEqual(p.shape, (150, 3)) + self.assertGreaterEqual(p.min(), 0) + self.assertLessEqual(p.max(), 1) + np.testing.assert_almost_equal(p.sum(axis=1), np.ones(150)) + + def test_SimpleRandomForest_regression(self): + data = Orange.data.Table('housing') + lrn = SimpRandForestReg() + clf = lrn(data) + p = clf(data) + self.assertEqual(p.shape, (len(data),)) + + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/test_simple_tree.py b/pyminer2/tests/test_simple_tree.py new file mode 100644 index 0000000000000000000000000000000000000000..475f504fc65e49c6b175c96a9a43b1b47312fe33 --- /dev/null +++ b/pyminer2/tests/test_simple_tree.py @@ -0,0 +1,172 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import pickle + +import numpy as np + +import Orange +from Orange.classification import SimpleTreeLearner as SimpleTreeCls +from Orange.regression import SimpleTreeLearner as SimpleTreeReg +from Orange.data import ContinuousVariable, Domain, DiscreteVariable, Table +from Orange.tests import test_filename + + +class TestSimpleTreeLearner(unittest.TestCase): + def setUp(self): + self.N = 50 + self.Mi = 3 + self.Mf = 3 + self.cls_vals = 3 + np.random.seed(42) + Xi = np.random.randint(0, 2, (self.N, self.Mi)).astype(np.float64) + Xf = np.random.normal(0, 1, (self.N, self.Mf)).astype(np.float64) + X = np.hstack((Xi, Xf)) + y_cls = np.random.randint(0, self.cls_vals, self.N).astype(np.float64) + y_reg = np.random.normal(0, 1, self.N).astype(np.float64) + + X[np.random.random(X.shape) < 0.1] = np.nan + y_cls[np.random.random(self.N) < 0.1] = np.nan + y_reg[np.random.random(self.N) < 0.1] = np.nan + + di = [Orange.data.domain.DiscreteVariable( + 'd{}'.format(i), ["0", "1"]) for i in range(self.Mi)] + df = [Orange.data.domain.ContinuousVariable( + 'c{}'.format(i)) for i in range(self.Mf)] + dcls = Orange.data.domain.DiscreteVariable('yc', ["0", "1", "2"]) + dreg = Orange.data.domain.ContinuousVariable('yr') + domain_cls = Orange.data.domain.Domain(di + df, dcls) + domain_reg = Orange.data.domain.Domain(di + df, dreg) + + self.data_cls = Orange.data.Table.from_numpy(domain_cls, X, y_cls) + self.data_reg = Orange.data.Table.from_numpy(domain_reg, X, y_reg) + + def test_SimpleTree_classification(self): + lrn = SimpleTreeCls() + clf = lrn(self.data_cls) + p = clf(self.data_cls, clf.Probs) + self.assertEqual(p.shape, (self.N, self.cls_vals)) + self.assertAlmostEqual(p.min(), 0) + self.assertAlmostEqual(p.max(), 1) + np.testing.assert_almost_equal(p.sum(axis=1), np.ones(self.N)) + + def test_SimpleTree_classification_pickle(self): + lrn = SimpleTreeCls() + clf = lrn(self.data_cls) + p = clf(self.data_cls, clf.Probs) + clf_ = pickle.loads(pickle.dumps(clf)) + p_ = clf_(self.data_cls, clf.Probs) + np.testing.assert_almost_equal(p, p_) + + def test_SimpleTree_classification_tree(self): + lrn = SimpleTreeCls(min_instances=6, max_majority=0.7) + clf = lrn(self.data_cls) + self.assertEqual( + clf.dumps_tree(clf.node), + '{ 1 4 -1.17364 { 1 5 0.37564 { 2 0.00 0.00 0.56 } ' + '{ 2 0.00 3.00 1.14 } } { 1 4 -0.41863 { 1 5 0.14592 ' + '{ 2 3.54 0.54 0.70 } { 2 2.46 0.46 2.47 } } { 1 4 0.24404 ' + '{ 1 4 0.00654 { 1 3 -0.15750 { 2 1.00 0.00 0.45 } ' + '{ 2 1.00 3.00 0.48 } } { 2 1.00 5.00 0.70 } } { 1 5 0.32635 ' + '{ 2 0.52 2.52 4.21 } { 2 2.48 3.48 1.30 } } } } }') + + def test_SimpleTree_regression(self): + lrn = SimpleTreeReg() + clf = lrn(self.data_reg) + p = clf(self.data_reg) + self.assertEqual(p.shape, (self.N,)) + + def test_SimpleTree_regression_pickle(self): + pass + + def test_SimpleTree_regression_tree(self): + lrn = SimpleTreeReg(min_instances=5) + clf = lrn(self.data_reg) + self.assertEqual( + clf.dumps_tree(clf.node), + '{ 0 2 { 1 4 0.13895 { 1 4 -0.32607 { 2 4.60993 1.71141 } ' + '{ 2 4.96454 3.56122 } } { 2 7.09220 -4.32343 } } { 1 4 -0.35941 ' + '{ 0 0 { 1 5 -0.20027 { 2 3.54255 0.95095 } { 2 5.50000 -5.56049 } ' + '} { 2 7.62411 2.03615 } } { 1 5 0.40797 { 1 3 0.83459 ' + '{ 2 3.71094 0.27028 } { 2 5.18490 3.70920 } } { 2 5.77083 5.93398 ' + '} } } }') + + def test_SimpleTree_single_instance(self): + data = Orange.data.Table('iris') + lrn = SimpleTreeCls() + clf = lrn(data) + for ins in data[::20]: + clf(ins) + val, prob = clf(ins, clf.ValueProbs) + self.assertEqual(sum(prob), 1) + + def test_SimpleTree_to_string_classification(self): + domain = Domain([DiscreteVariable(name='d1', values='ef'), + ContinuousVariable(name='c1')], + DiscreteVariable(name='cls', values='abc')) + data = Table.from_list(domain, [['e', 1, 'a'], + ['e', 1, 'b'], + ['e', 2, 'b'], + ['f', 2, "c"], + ["e", 3, "a"], + ['f', 3, "c"]]) + lrn = SimpleTreeCls(min_instances=1) + clf = lrn(data) + clf_str = clf.to_string() + res = '\n' \ + 'd1 ([2.0, 2.0, 2.0])\n' \ + ': e\n' \ + ' c1 ([2.0, 2.0, 0.0])\n' \ + ' : <=2.5\n' \ + ' c1 ([1.0, 2.0, 0.0])\n' \ + ' : <=1.5 --> a ([1.0, 1.0, 0.0])\n' \ + ' : >1.5 --> b ([0.0, 1.0, 0.0])\n' \ + ' : >2.5 --> a ([1.0, 0.0, 0.0])\n' \ + ': f --> c ([0.0, 0.0, 2.0])' + self.assertEqual(clf_str, res) + + def test_SimpleTree_to_string_regression(self): + domain = Domain([DiscreteVariable(name='d1', values='ef'), + ContinuousVariable(name='c1')], + ContinuousVariable(name='cls')) + data = Table.from_list(domain, [['e', 1, 10], + ['e', 1, 20], + ['e', 2, 20], + ['f', 2, 30], + ["e", 3, 10], + ['f', 3, 30]]) + lrn = SimpleTreeReg(min_instances=1) + reg = lrn(data) + reg_str = reg.to_string() + res = '\n' \ + 'd1 (20: 6.0)\n' \ + ': e\n' \ + ' c1 (15: 4.0)\n' \ + ' : <=2.5\n' \ + ' c1 (16.6667: 3.0)\n' \ + ' : <=1.5 --> (15: 2.0)\n' \ + ' : >1.5 --> (20: 1.0)\n' \ + ' : >2.5 --> (10: 1.0)\n' \ + ': f --> (30: 2.0)' + self.assertEqual(reg_str, res) + + def test_SimpleTree_to_string_cls_decimals(self): + data = Table(test_filename("datasets/lenses.tab")) + lrn = SimpleTreeReg(min_instances=1) + cls = lrn(data) + cls_str = cls.to_string() + res = ' astigmatic ([4.0, 3.0, 5.0])' + self.assertEqual(cls_str.split("\n")[3], res) + + def test_SimpleTree_to_string_reg_decimals(self): + data = Table("housing") + lrn = SimpleTreeReg(min_instances=1) + reg = lrn(data) + reg_str = reg.to_string() + res = ' LSTAT (19.9: 430.0)' + self.assertEqual(reg_str.split("\n")[3], res) + + +if __name__ == '__main__': + unittest.main() diff --git a/pyminer2/tests/test_softmax_regression.py b/pyminer2/tests/test_softmax_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..87c554d68bfdfbe6523c1cff8237a7855e2fb361 --- /dev/null +++ b/pyminer2/tests/test_softmax_regression.py @@ -0,0 +1,52 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest + +from Orange.data import Table +from Orange.classification import Model, SoftmaxRegressionLearner +from Orange.evaluation import CrossValidation, CA + + +class TestSoftmaxRegressionLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + + def test_SoftmaxRegression(self): + learner = SoftmaxRegressionLearner() + cv = CrossValidation(k=3) + results = cv(self.iris, [learner]) + ca = CA(results) + self.assertGreater(ca, 0.9) + self.assertLess(ca, 1.0) + + def test_SoftmaxRegressionPreprocessors(self): + table = self.iris.copy() + table.X[:, 2] = table.X[:, 2] * 0.001 + table.X[:, 3] = table.X[:, 3] * 0.001 + learners = [SoftmaxRegressionLearner(preprocessors=[]), + SoftmaxRegressionLearner()] + cv = CrossValidation(k=10) + results = cv(table, learners) + ca = CA(results) + + self.assertLess(ca[0], ca[1]) + + def test_probability(self): + learn = SoftmaxRegressionLearner() + clf = learn(self.iris) + p = clf(self.iris, ret=Model.Probs) + self.assertLess(abs(p.sum(axis=1) - 1).all(), 1e-6) + + def test_predict_table(self): + learner = SoftmaxRegressionLearner() + c = learner(self.iris) + c(self.iris) + vals, probs = c(self.iris, c.ValueProbs) + + def test_predict_numpy(self): + learner = SoftmaxRegressionLearner() + c = learner(self.iris) + c(self.iris.X) + vals, probs = c(self.iris.X, c.ValueProbs) diff --git a/pyminer2/tests/test_sparse_reader.py b/pyminer2/tests/test_sparse_reader.py new file mode 100644 index 0000000000000000000000000000000000000000..08f56db5d55bab4db3e99f887103583d71abcbf4 --- /dev/null +++ b/pyminer2/tests/test_sparse_reader.py @@ -0,0 +1,92 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import os +import tempfile +import unittest + +import numpy as np + +from Orange.data import _io + + +simple_file = """\ +abc, def, g=1, h , ij k =5, t # ignore this, foo=42 + +def , g , h,ij,kl=4,m,,, +# nothing here +\t\t\tdef +""" + +complex_file = """\ +abc, g=1, h , ij | k =5, t # ignore this, foo=42 + +, g , h,ij|,kl=4, k ;m,,, +# nothing here +\t\t\t;def +""" + +class TestTabReader(unittest.TestCase): + def test_read_simple(self): + f = tempfile.NamedTemporaryFile(delete=False) + f.write(simple_file.encode("ascii")) + f.close() + try: + X, Y, metas, attr_indices, class_indices, meta_indices = \ + _io.sparse_read_float(f.name.encode("ascii")) + + self.assertEqual( + attr_indices, + {b"abc": 0, b"def": 1, b"g": 2, b"h": 3, b"ij k": 4, b"t": 5, + b"ij": 6, b"kl": 7, b"m": 8}) + np.testing.assert_almost_equal(X.data, [1, 1, 1, 1, 5, 1, + 1, 1, 1, 1, 4, 1, + 1]) + np.testing.assert_equal(X.indices, [0, 1, 2, 3, 4, 5, + 1, 2, 3, 6, 7, 8, + 1]) + np.testing.assert_equal(X.indptr, [0, 6, 12, 13]) + + self.assertEqual(class_indices, {}) + self.assertIsNone(Y) + + self.assertEqual(meta_indices, {}) + self.assertIsNone(metas) + finally: + os.remove(f.name) + + + # for readability, pylint: disable=bad-whitespace + def test_read_complex(self): + f = tempfile.NamedTemporaryFile(delete=False) + f.write(complex_file.encode("ascii")) + f.close() + try: + X, Y, metas, attr_indices, class_indices, meta_indices = \ + _io.sparse_read_float(f.name.encode("ascii")) + + self.assertEqual( + attr_indices, + {b"abc": 0, b"g": 1, b"h": 2, b"ij": 3}) + np.testing.assert_equal(X.data, [1, 1, 1, 1, 1, 1, 1]) + np.testing.assert_equal(X.indices, [0, 1, 2, 3, 1, 2, 3]) + np.testing.assert_equal(X.indptr, [0, 4, 7, 7]) + + + self.assertEqual(class_indices, {b"k": 0, b"t": 1, b"kl": 2}) + np.testing.assert_equal(Y.data, [5, 1, 1, 4]) + np.testing.assert_equal(Y.indices, [0, 1, 0, 2]) + np.testing.assert_equal(Y.indptr, [0, 2, 4, 4]) + + self.assertEqual(meta_indices, {b"m": 0, b"def": 1}) + np.testing.assert_equal(metas.data, [ 1, 1]) + np.testing.assert_equal(metas.indices, [ 0, 1]) + np.testing.assert_equal(metas.indptr, [0, 0, 1, 2]) + finally: + os.remove(f.name) + + + # TODO checks for quotes, escapes, error checking + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_sparse_table.py b/pyminer2/tests/test_sparse_table.py new file mode 100644 index 0000000000000000000000000000000000000000..d4a1dbcfee695b6a44a0e51db5ea2f021f9b2f96 --- /dev/null +++ b/pyminer2/tests/test_sparse_table.py @@ -0,0 +1,63 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import warnings + +import numpy as np +from scipy.sparse import csr_matrix, SparseEfficiencyWarning + +from Orange import data +from Orange.data import Table +from Orange.tests import test_table as tabletests + + +class InterfaceTest(tabletests.InterfaceTest): + def setUp(self): + super().setUp() + self.table = data.Table.from_numpy( + self.domain, + csr_matrix(self.table.X), + csr_matrix(self.table.Y), + ) + + def test_row_assignment(self): + # This warning will appear in actual code that assigns rows of + # sparse matrix, which is OK, but We don't need it in test outputs + warnings.filterwarnings("ignore", ".*", SparseEfficiencyWarning) + super().test_row_assignment() + + def test_value_assignment(self): + # This warning will appear in actual code that assigns rows of + # sparse matrix, which is OK, but We don't need it in test outputs + warnings.filterwarnings("ignore", ".*", SparseEfficiencyWarning) + super().test_value_assignment() + + def test_str(self): + iris = Table('iris') + iris.X, iris.Y = csr_matrix(iris.X), csr_matrix(iris.Y) + str(iris) + + def test_Y_setter_1d(self): + iris = Table('iris') + assert iris.Y.shape == (150,) + iris.Y = csr_matrix(iris.Y) + # We expect the Y shape to match the X shape, which is (150, 4) in iris + self.assertEqual(iris.Y.shape, (150,)) + + def test_Y_setter_2d(self): + iris = Table('iris') + assert iris.Y.shape == (150,) + # Convert iris.Y to (150, 1) shape + new_y = iris.Y[:, np.newaxis] + iris.Y = np.hstack((new_y, new_y)) + iris.Y = csr_matrix(iris.Y) + # We expect the Y shape to match the X shape, which is (150, 4) in iris + self.assertEqual(iris.Y.shape, (150, 2)) + + def test_Y_setter_2d_single_instance(self): + iris = Table('iris')[:1] + # Convert iris.Y to (1, 1) shape + new_y = iris.Y[:, np.newaxis] + iris.Y = np.hstack((new_y, new_y)) + iris.Y = csr_matrix(iris.Y) + # We expect the Y shape to match the X shape, which is (1, 4) in iris + self.assertEqual(iris.Y.shape, (1, 2)) diff --git a/pyminer2/tests/test_stack.py b/pyminer2/tests/test_stack.py new file mode 100644 index 0000000000000000000000000000000000000000..c52ff229d2132738d6047b5640f4ac39bdb6186a --- /dev/null +++ b/pyminer2/tests/test_stack.py @@ -0,0 +1,28 @@ +import unittest + +from Orange.data import Table +from Orange.ensembles.stack import StackedFitter +from Orange.evaluation import CA, CrossValidation, MSE +from Orange.modelling import KNNLearner, TreeLearner + + +class TestStackedFitter(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + cls.housing = Table('housing') + + def test_classification(self): + sf = StackedFitter([TreeLearner(), KNNLearner()]) + cv = CrossValidation(k=3) + results = cv(self.iris, [sf]) + ca = CA(results) + self.assertGreater(ca, 0.9) + + def test_regression(self): + sf = StackedFitter([TreeLearner(), KNNLearner()]) + cv = CrossValidation(k=3, random_state=0) + results = cv(self.housing[:50], [sf, TreeLearner(), KNNLearner()]) + mse = MSE()(results) + self.assertLess(mse[0], mse[1]) + self.assertLess(mse[0], mse[2]) diff --git a/pyminer2/tests/test_statistics.py b/pyminer2/tests/test_statistics.py new file mode 100644 index 0000000000000000000000000000000000000000..3ce354a2c81aa493e21bc8e90c6a8e5b796743e6 --- /dev/null +++ b/pyminer2/tests/test_statistics.py @@ -0,0 +1,798 @@ +# pylint: disable=no-self-use +import unittest +import warnings +from itertools import chain +from functools import partial, wraps + +import numpy as np +from scipy.sparse import csr_matrix, issparse, lil_matrix, csc_matrix, \ + SparseEfficiencyWarning + +from Orange.data.util import assure_array_dense +from Orange.statistics.util import bincount, countnans, contingency, digitize, \ + mean, nanmax, nanmean, nanmedian, nanmin, nansum, nanunique, stats, std, \ + unique, var, nanstd, nanvar, nanmode, nan_to_num, FDR, isnan, any_nan, \ + all_nan +from sklearn.utils import check_random_state + + +def dense_sparse(test_case): + # type: (Callable) -> Callable + """Run a single test case on both dense and sparse data.""" + @wraps(test_case) + def _wrapper(self): + + def sparse_with_explicit_zero(x, array): + """Inject one explicit zero into a sparse array.""" + np_array, sp_array = np.atleast_2d(x), array(x) + assert issparse(sp_array), 'Can not inject explicit zero into non-sparse matrix' + + zero_indices = np.argwhere(np_array == 0) + if zero_indices.size: + with warnings.catch_warnings(): + # this is just inefficiency in tests, not the tested code + warnings.filterwarnings("ignore", ".*", + SparseEfficiencyWarning) + sp_array[tuple(zero_indices[0])] = 0 + + return sp_array + + # Make sure to call setUp and tearDown methods in between test runs so + # any widget state doesn't interfere between tests + def _setup_teardown(): + self.tearDown() + self.setUp() + + test_case(self, np.array) + _setup_teardown() + test_case(self, csr_matrix) + _setup_teardown() + test_case(self, csc_matrix) + _setup_teardown() + test_case(self, partial(sparse_with_explicit_zero, array=csr_matrix)) + _setup_teardown() + test_case(self, partial(sparse_with_explicit_zero, array=csc_matrix)) + + return _wrapper + + +class TestUtil(unittest.TestCase): + def setUp(self): + nan = float('nan') + self.data = [ + np.array([ + [0., 1., 0., nan, 3., 5.], + [0., 0., nan, nan, 5., nan], + [0., 0., 0., nan, 7., 6.]]), + np.zeros((2, 3)), + np.ones((2, 3)), + ] + + def test_contingency(self): + x = np.array([0, 1, 0, 2, np.nan, np.nan]) + y = np.array([0, 0, 1, np.nan, 0, np.nan]) + cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2) + np.testing.assert_equal(cont_table, [[1, 1, 0], + [1, 0, 0], + [0, 0, 0]]) + np.testing.assert_equal(col_nans, [1, 0, 0]) + np.testing.assert_equal(row_nans, [0, 0, 1]) + self.assertEqual(1, nans) + + def test_weighted_contingency(self): + x = np.array([0, 1, 0, 2, np.nan, np.nan]) + y = np.array([0, 0, 1, np.nan, 0, np.nan]) + w = np.array([1, 2, 2, 3, 4, 2]) + cont_table, col_nans, row_nans, nans = contingency( + x, y, 2, 2, weights=w) + np.testing.assert_equal(cont_table, [[1, 2, 0], + [2, 0, 0], + [0, 0, 0]]) + np.testing.assert_equal(col_nans, [4, 0, 0]) + np.testing.assert_equal(row_nans, [0, 0, 3]) + self.assertEqual(2, nans) + + def test_stats(self): + X = np.arange(4).reshape(2, 2).astype(float) + X[1, 1] = np.nan + np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2], + [1, 1, 1, 0, 1, 1]]) + # empty table should return ~like metas + X = X[:0] + np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0], + [np.inf, -np.inf, 0, 0, 0, 0]]) + + def test_stats_sparse(self): + X = csr_matrix(np.identity(5)) + np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1], + [0, 1, .2, 0, 4, 1], + [0, 1, .2, 0, 4, 1], + [0, 1, .2, 0, 4, 1], + [0, 1, .2, 0, 4, 1]]) + + # assure last two columns have just zero elements + X = X[:3] + np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1], + [0, 1, 1/3, 0, 2, 1], + [0, 1, 1/3, 0, 2, 1], + [0, 0, 0, 0, 3, 0], + [0, 0, 0, 0, 3, 0]]) + + def test_stats_weights(self): + X = np.arange(4).reshape(2, 2).astype(float) + weights = np.array([1, 3]) + np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2], + [1, 3, 2.5, 0, 0, 2]]) + + X = np.arange(4).reshape(2, 2).astype(object) + np.testing.assert_equal(stats(X, weights), stats(X)) + + def test_stats_weights_sparse(self): + X = np.arange(4).reshape(2, 2).astype(float) + X = csr_matrix(X) + weights = np.array([1, 3]) + np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1], + [1, 3, 2.5, 0, 0, 2]]) + + def test_stats_non_numeric(self): + X = np.array([ + ["", "a", np.nan, 0], + ["a", "", np.nan, 1], + ["a", "b", 0, 0], + ], dtype=object) + np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2], + [np.inf, -np.inf, 0, 0, 1, 2], + [np.inf, -np.inf, 0, 0, 2, 1], + [np.inf, -np.inf, 0, 0, 0, 3]]) + + def test_nanmin_nanmax(self): + warnings.filterwarnings("ignore", r".*All-NaN slice encountered.*") + for X in self.data: + X_sparse = csr_matrix(X) + for axis in [None, 0, 1]: + np.testing.assert_array_equal( + nanmin(X, axis=axis), + np.nanmin(X, axis=axis)) + + np.testing.assert_array_equal( + nanmin(X_sparse, axis=axis), + np.nanmin(X, axis=axis)) + + np.testing.assert_array_equal( + nanmax(X, axis=axis), + np.nanmax(X, axis=axis)) + + np.testing.assert_array_equal( + nanmax(X_sparse, axis=axis), + np.nanmax(X, axis=axis)) + + @dense_sparse + def test_nansum(self, array): + for X in self.data: + X_sparse = array(X) + np.testing.assert_array_equal( + nansum(X_sparse), + np.nansum(X)) + + def test_mean(self): + # This warning is not unexpected and it's correct + warnings.filterwarnings("ignore", r".*mean\(\) resulted in nan.*") + for X in self.data: + X_sparse = csr_matrix(X) + np.testing.assert_array_equal( + mean(X_sparse), + np.mean(X)) + + with self.assertWarns(UserWarning): + mean([1, np.nan, 0]) + + def test_nanmode(self): + X = np.array([[np.nan, np.nan, 1, 1], + [2, np.nan, 1, 1]]) + mode, count = nanmode(X, 0) + np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]]) + np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]]) + mode, count = nanmode(X, 1) + np.testing.assert_array_equal(mode, [[1], [1]]) + np.testing.assert_array_equal(count, [[2], [2]]) + + @dense_sparse + def test_nanmedian(self, array): + for X in self.data: + X_sparse = array(X) + np.testing.assert_array_equal( + nanmedian(X_sparse), + np.nanmedian(X)) + + @dense_sparse + def test_nanmedian_more_nonzeros(self, array): + X = np.ones((10, 10)) + X[:5, 0] = np.nan + X[:6, 1] = 0 + X_sparse = array(X) + np.testing.assert_array_equal( + nanmedian(X_sparse), + np.nanmedian(X) + ) + + def test_var(self): + for data in self.data: + for axis in chain((None,), range(len(data.shape))): + # Can't use array_equal here due to differences on 1e-16 level + np.testing.assert_array_almost_equal( + var(csr_matrix(data), axis=axis), + np.var(data, axis=axis) + ) + + def test_var_with_ddof(self): + x = np.random.uniform(0, 10, (20, 100)) + for axis in [None, 0, 1]: + np.testing.assert_almost_equal( + np.var(x, axis=axis, ddof=10), + var(csr_matrix(x), axis=axis, ddof=10), + ) + + @dense_sparse + def test_nanvar(self, array): + for X in self.data: + X_sparse = array(X) + np.testing.assert_array_equal( + nanvar(X_sparse), + np.nanvar(X)) + + def test_nanvar_with_ddof(self): + x = np.random.uniform(0, 10, (20, 100)) + np.fill_diagonal(x, np.nan) + for axis in [None, 0, 1]: + np.testing.assert_almost_equal( + np.nanvar(x, axis=axis, ddof=10), + nanvar(csr_matrix(x), axis=axis, ddof=10), + ) + + def test_std(self): + for data in self.data: + for axis in chain((None,), range(len(data.shape))): + # Can't use array_equal here due to differences on 1e-16 level + np.testing.assert_array_almost_equal( + std(csr_matrix(data), axis=axis), + np.std(data, axis=axis) + ) + + def test_std_with_ddof(self): + x = np.random.uniform(0, 10, (20, 100)) + for axis in [None, 0, 1]: + np.testing.assert_almost_equal( + np.std(x, axis=axis, ddof=10), + std(csr_matrix(x), axis=axis, ddof=10), + ) + + @dense_sparse + def test_nanstd(self, array): + for X in self.data: + X_sparse = array(X) + np.testing.assert_array_equal( + nanstd(X_sparse), + np.nanstd(X)) + + def test_nanstd_with_ddof(self): + x = np.random.uniform(0, 10, (20, 100)) + for axis in [None, 0, 1]: + np.testing.assert_almost_equal( + np.nanstd(x, axis=axis, ddof=10), + nanstd(csr_matrix(x), axis=axis, ddof=10), + ) + + def test_FDR(self): + p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001]) + np.testing.assert_almost_equal( + np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]), + FDR(p_values), decimal=5) + + def test_FDR_dependent(self): + p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001]) + np.testing.assert_almost_equal( + np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]), + FDR(p_values, dependent=True), decimal=5) + + def test_FDR_m(self): + p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001]) + np.testing.assert_almost_equal( + np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]), + FDR(p_values, m=3), decimal=5) + + def test_FDR_no_values(self): + self.assertIsNone(FDR(None)) + self.assertIsNone(FDR([])) + self.assertIsNone(FDR([0.0002, 0.0004], m=0)) + + def test_FDR_list(self): + p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001] + result = FDR(p_values) + self.assertIsInstance(result, list) + np.testing.assert_almost_equal( + np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]), + result, decimal=5) + + +class TestNanmean(unittest.TestCase): + def setUp(self): + self.random_state = check_random_state(42) + self.x = self.random_state.uniform(size=(10, 5)) + np.fill_diagonal(self.x, np.nan) + + @dense_sparse + def test_axis_none(self, array): + np.testing.assert_almost_equal( + np.nanmean(self.x), nanmean(array(self.x)) + ) + + @dense_sparse + def test_axis_0(self, array): + np.testing.assert_almost_equal( + np.nanmean(self.x, axis=0), nanmean(array(self.x), axis=0) + ) + + @dense_sparse + def test_axis_1(self, array): + np.testing.assert_almost_equal( + np.nanmean(self.x, axis=1), nanmean(array(self.x), axis=1) + ) + + +class TestDigitize(unittest.TestCase): + def setUp(self): + # pylint: disable=bad-whitespace + self.data = [ + np.array([ + [0., 1., 0., np.nan, 3., 5.], + [0., 0., np.nan, np.nan, 5., np.nan], + [0., 0., 0., np.nan, 7., 6.]]), + np.zeros((2, 3)), + np.ones((2, 3)), + ] + + @dense_sparse + def test_digitize(self, array): + for x_original in self.data: + x = array(x_original) + bins = np.arange(-2, 2) + + x_shape = x.shape + np.testing.assert_array_equal( + np.digitize(x_original.flatten(), bins).reshape(x_shape), + digitize(x, bins), + ) + + @dense_sparse + def test_digitize_right(self, array): + for x_original in self.data: + x = array(x_original) + bins = np.arange(-2, 2) + + x_shape = x.shape + np.testing.assert_array_equal( + np.digitize(x_original.flatten(), bins, right=True).reshape(x_shape), + digitize(x, bins, right=True) + ) + + @dense_sparse + def test_digitize_1d_array(self, array): + """A consistent return shape must be returned for both sparse and dense.""" + x_original = np.array([0, 1, 1, 0, np.nan, 0, 1]) + x = array(x_original) + bins = np.arange(-2, 2) + + x_shape = x_original.shape + np.testing.assert_array_equal( + [np.digitize(x_original.flatten(), bins).reshape(x_shape)], + digitize(x, bins), + ) + + def test_digitize_sparse_zeroth_bin(self): + # Setup the data so that the '0's will fit into the '0'th bin. + data = csr_matrix([ + [0, 0, 0, 1, 1, 0, 0, 1, 0], + [0, 0, 1, 1, 0, 0, 1, 0, 0], + ]) + bins = np.array([1]) + # Then digitize should return a sparse matrix + self.assertTrue(issparse(digitize(data, bins))) + + +class TestCountnans(unittest.TestCase): + @dense_sparse + def test_1d_array(self, array): + x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]) + self.assertEqual(countnans(x), 2) + + @dense_sparse + def test_1d_array_with_axis_0(self, array): + x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]) + expected = 2 + + self.assertEqual(countnans(x, axis=0), expected) + + @dense_sparse + def test_1d_array_with_axis_1_raises_exception(self, array): + with self.assertRaises(ValueError): + countnans(array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]), axis=1) + + @dense_sparse + def test_shape_matches_dense_and_sparse(self, array): + x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1], + [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]]) + expected = 4 + + self.assertEqual(countnans(x), expected) + + @dense_sparse + def test_shape_matches_dense_and_sparse_with_axis_0(self, array): + x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1], + [1, 2, 2, 1, np.nan, 1, 2, np.nan, 3, 3]]) + expected = [0, 0, 0, 0, 1, 1, 0, 2, 0, 0] + + np.testing.assert_equal(countnans(x, axis=0), expected) + + @dense_sparse + def test_shape_matches_dense_and_sparse_with_axis_1(self, array): + x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1], + [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]]) + expected = [2, 2] + + np.testing.assert_equal(countnans(x, axis=1), expected) + + @dense_sparse + def test_2d_matrix(self, array): + x = array([[1, np.nan, 1, 2], + [2, np.nan, 2, 3]]) + expected = 2 + + self.assertEqual(countnans(x), expected) + + @dense_sparse + def test_on_columns(self, array): + x = array([[1, np.nan, 1, 2], + [2, np.nan, 2, 3]]) + expected = [0, 2, 0, 0] + + np.testing.assert_equal(countnans(x, axis=0), expected) + + @dense_sparse + def test_on_rows(self, array): + x = array([[1, np.nan, 1, 2], + [2, np.nan, 2, 3]]) + expected = [1, 1] + + np.testing.assert_equal(countnans(x, axis=1), expected) + + @dense_sparse + def test_1d_weights_with_axis_0(self, array): + x = array([[1, 1, np.nan, 1], + [np.nan, 1, 1, 1]]) + w = np.array([0.5, 1, 1, 1]) + + np.testing.assert_equal(countnans(x, w, axis=0), [.5, 0, 1, 0]) + + @dense_sparse + def test_1d_weights_with_axis_1(self, array): + x = array([[1, 1, np.nan, 1], + [np.nan, 1, 1, 1]]) + w = np.array([0.5, 1]) + + np.testing.assert_equal(countnans(x, w, axis=1), [.5, 1]) + + @dense_sparse + def test_2d_weights(self, array): + # pylint: disable=bad-whitespace + x = array([[np.nan, np.nan, 1, 1 ], + [ 0, np.nan, 2, np.nan ]]) + w = np.array([[1, 2, 3, 4], + [5, 6, 7, 8]]) + + np.testing.assert_equal(countnans(x, w), 17) + np.testing.assert_equal(countnans(x, w, axis=0), [1, 8, 0, 8]) + np.testing.assert_equal(countnans(x, w, axis=1), [3, 14]) + + @dense_sparse + def test_dtype(self, array): + x = array([0, np.nan, 2, 3]) + w = np.array([0, 1.5, 0, 0]) + + self.assertIsInstance(countnans(x, w, dtype=np.int32), np.int32) + self.assertEqual(countnans(x, w, dtype=np.int32), 1) + self.assertIsInstance(countnans(x, w, dtype=np.float64), np.float64) + self.assertEqual(countnans(x, w, dtype=np.float64), 1.5) + + +class TestBincount(unittest.TestCase): + @dense_sparse + def test_count_nans(self, array): + x = array([0, 0, 1, 2, np.nan, 2]) + expected = 1 + + np.testing.assert_equal(bincount(x)[1], expected) + + # object arrays cannot be converted to sparse, so test only for dense + def test_count_nans_objectarray(self): + x = np.array([0, 0, 1, 2, np.nan, 2], dtype=object) + expected = 1 + + np.testing.assert_equal(bincount(x)[1], expected) + + @dense_sparse + def test_adds_empty_bins(self, array): + x = array([0, 1, 3, 5]) + expected = [1, 1, 0, 1, 0, 1] + + np.testing.assert_equal(bincount(x)[0], expected) + + @dense_sparse + def test_maxval_adds_empty_bins(self, array): + x = array([1, 1, 1, 2, 3, 2]) + max_val = 5 + expected = [0, 3, 2, 1, 0, 0] + + np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected) + + @dense_sparse + def test_maxval_doesnt_truncate_values_when_too_small(self, array): + x = array([1, 1, 1, 2, 3, 2]) + max_val = 1 + expected = [0, 3, 2, 1] + + np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected) + + @dense_sparse + def test_minlength_adds_empty_bins(self, array): + x = array([1, 1, 1, 2, 3, 2]) + minlength = 5 + expected = [0, 3, 2, 1, 0] + + np.testing.assert_equal(bincount(x, minlength=minlength)[0], expected) + + @dense_sparse + def test_weights(self, array): + x = array([0, 0, 1, 1, 2, 2, 3, 3]) + w = np.array([1, 2, 0, 0, 1, 1, 0, 1]) + + expected = [3, 0, 2, 1] + np.testing.assert_equal(bincount(x, w)[0], expected) + + @dense_sparse + def test_weights_with_nans(self, array): + x = array([0, 0, 1, 1, np.nan, 2, np.nan, 3]) + w = np.array([1, 2, 0, 0, 1, 1, 0, 1]) + + expected = [3, 0, 1, 1] + np.testing.assert_equal(bincount(x, w)[0], expected) + + @dense_sparse + def test_weights_with_transposed_x(self, array): + x = array([0, 0, 1, 1, 2, 2, 3, 3]).T + w = np.array([1, 2, 0, 0, 1, 1, 0, 1]) + + expected = [3, 0, 2, 1] + np.testing.assert_equal(bincount(x, w)[0], expected) + + @dense_sparse + def test_all_nans(self, array): + x = array([np.nan] * 5) + expected = [] + + np.testing.assert_equal(bincount(x)[0], expected) + + @dense_sparse + def test_all_zeros_or_nans(self, array): + """Sparse arrays with only nans with no explicit zeros will have no non + zero indices. Check that this counts the zeros properly.""" + x = array([np.nan] * 5 + [0] * 5) + expected = [5] + + np.testing.assert_equal(bincount(x)[0], expected) + + +class TestUnique(unittest.TestCase): + @dense_sparse + def test_returns_unique_values(self, array): + # pylint: disable=bad-whitespace + x = array([[-1., 1., 0., 2., 3., np.nan], + [ 0., 0., 0., 3., 5., np.nan], + [-1., 0., 0., 1., 7., 6.]]) + expected = [-1, 0, 1, 2, 3, 5, 6, 7, np.nan, np.nan] + + np.testing.assert_equal(unique(x, return_counts=False), expected) + + @dense_sparse + def test_returns_counts(self, array): + # pylint: disable=bad-whitespace + x = array([[-1., 1., 0., 2., 3., np.nan], + [ 0., 0., 0., 3., 5., np.nan], + [-1., 0., 0., 1., 7., 6.]]) + expected = [2, 6, 2, 1, 2, 1, 1, 1, 1, 1] + + np.testing.assert_equal(unique(x, return_counts=True)[1], expected) + + def test_sparse_explicit_zeros(self): + # Use `lil_matrix` to fix sparse warning for matrix construction + x = lil_matrix(np.eye(3)) + x[0, 1] = 0 + x[1, 0] = 0 + x = x.tocsr() + # Test against identity matrix + y = csr_matrix(np.eye(3)) + + np.testing.assert_array_equal( + unique(y, return_counts=True), + unique(x, return_counts=True), + ) + + @dense_sparse + def test_nanunique_ignores_nans_in_values(self, array): + # pylint: disable=bad-whitespace + x = array([[-1., 1., 0., 2., 3., np.nan], + [ 0., 0., 0., 3., 5., np.nan], + [-1., 0., 0., 1., 7., 6.]]) + expected = [-1, 0, 1, 2, 3, 5, 6, 7] + + np.testing.assert_equal(nanunique(x, return_counts=False), expected) + + @dense_sparse + def test_nanunique_ignores_nans_in_counts(self, array): + # pylint: disable=bad-whitespace + x = array([[-1., 1., 0., 2., 3., np.nan], + [ 0., 0., 0., 3., 5., np.nan], + [-1., 0., 0., 1., 7., 6.]]) + expected = [2, 6, 2, 1, 2, 1, 1, 1] + + np.testing.assert_equal(nanunique(x, return_counts=True)[1], expected) + + +class TestNanToNum(unittest.TestCase): + @dense_sparse + def test_converts_invalid_values(self, array): + x = np.array([ + [np.nan, 0, 2, np.inf], + [-np.inf, np.nan, 1e-18, 2], + [np.nan, np.nan, np.nan, np.nan], + [np.inf, np.inf, np.inf, np.inf], + ]) + result = nan_to_num(array(x)) + np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x)) + + @dense_sparse + def test_preserves_valid_values(self, array): + x = np.arange(12).reshape((3, 4)) + result = nan_to_num(array(x)) + np.testing.assert_equal(assure_array_dense(result), x) + np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x)) + + +class TestIsnan(unittest.TestCase): + def setUp(self) -> None: + # pylint: disable=bad-whitespace + self.x = np.array([ + [0., 1., 0., np.nan, 3., 5.], + [0., 0., np.nan, np.nan, 5., np.nan], + [0., 0., 0., np.nan, 7., 6.], + [0., 0., 0., 5., 7., 6.], + ]) + + @dense_sparse + def test_functionality(self, array): + expected = np.isnan(self.x) + result = isnan(array(self.x)) + np.testing.assert_equal(assure_array_dense(result), expected) + + @dense_sparse + def test_out(self, array): + x = array(self.x) + x_dtype = x.dtype + result = isnan(x, out=x) + self.assertIs(result, x) + self.assertEqual(x_dtype, result.dtype) + + +class TestAnyNans(unittest.TestCase): + def setUp(self) -> None: + # pylint: disable=bad-whitespace + self.x_with_nans = np.array([ + [0., 1., 0., np.nan, 3., 5.], + [0., 0., np.nan, np.nan, 5., np.nan], + [0., 0., 0., np.nan, 7., 6.], + [0., 0., 0., 5., 7., 6.], + ]) + self.x_no_nans = np.arange(12).reshape((3, 4)) + + @dense_sparse + def test_axis_none_without_nans(self, array): + self.assertFalse(any_nan(array(self.x_no_nans))) + + @dense_sparse + def test_axis_none_with_nans(self, array): + self.assertTrue(any_nan(array(self.x_with_nans))) + + @dense_sparse + def test_axis_0_without_nans(self, array): + expected = np.array([0, 0, 0, 0], dtype=bool) + result = any_nan(array(self.x_no_nans), axis=0) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_0_with_nans(self, array): + expected = np.array([0, 0, 1, 1, 0, 1], dtype=bool) + result = any_nan(array(self.x_with_nans), axis=0) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_1_without_nans(self, array): + expected = np.array([0, 0, 0], dtype=bool) + result = any_nan(array(self.x_no_nans), axis=1) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_1_with_nans(self, array): + expected = np.array([1, 1, 1, 0], dtype=bool) + result = any_nan(array(self.x_with_nans), axis=1) + np.testing.assert_equal(result, expected) + + +class TestAllNans(unittest.TestCase): + def setUp(self) -> None: + # pylint: disable=bad-whitespace + self.x_with_nans = np.array([ + [0., 1., 0., np.nan, 3., 5.], + [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], + [0., 0., 0., np.nan, 7., 6.], + [0., 0., 0., np.nan, 7., np.nan], + ]) + self.x_no_nans = np.arange(12).reshape((3, 4)) + self.x_only_nans = (np.ones(12) * np.nan).reshape((3, 4)) + + @dense_sparse + def test_axis_none_without_nans(self, array): + self.assertFalse(all_nan(array(self.x_no_nans))) + + @dense_sparse + def test_axis_none_with_nans(self, array): + self.assertTrue(all_nan(array(self.x_only_nans))) + + @dense_sparse + def test_axis_0_without_nans(self, array): + expected = np.array([0, 0, 0, 0], dtype=bool) + result = all_nan(array(self.x_no_nans), axis=0) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_0_with_nans(self, array): + expected = np.array([0, 0, 0, 1, 0, 0], dtype=bool) + result = all_nan(array(self.x_with_nans), axis=0) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_1_without_nans(self, array): + expected = np.array([0, 0, 0], dtype=bool) + result = all_nan(array(self.x_no_nans), axis=1) + np.testing.assert_equal(result, expected) + + @dense_sparse + def test_axis_1_with_nans(self, array): + expected = np.array([0, 1, 0, 0], dtype=bool) + result = all_nan(array(self.x_with_nans), axis=1) + np.testing.assert_equal(result, expected) + + +class TestNanModeFixedInScipy(unittest.TestCase): + + @unittest.expectedFailure + def test_scipy_nanmode_still_wrong(self): + import scipy.stats + X = np.array([[np.nan, np.nan, 1, 1], + [2, np.nan, 1, 1]]) + mode, count = scipy.stats.mode(X, 0) + np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]]) + np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]]) + mode, count = scipy.stats.mode(X, 1) + np.testing.assert_array_equal(mode, [[1], [1]]) + np.testing.assert_array_equal(count, [[2], [2]]) + # When Scipy's scipy.stats.mode works correcly, remove Orange.statistics.util.nanmode + # and this test. Also update requirements. diff --git a/pyminer2/tests/test_svm.py b/pyminer2/tests/test_svm.py new file mode 100644 index 0000000000000000000000000000000000000000..43d34757b90c450a7792382ec92f5cd08d21ff01 --- /dev/null +++ b/pyminer2/tests/test_svm.py @@ -0,0 +1,115 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import warnings + +import numpy as np +from sklearn.exceptions import ConvergenceWarning + +from Orange.classification import (SVMLearner, LinearSVMLearner, + NuSVMLearner, OneClassSVMLearner) +from Orange.regression import (SVRLearner, NuSVRLearner) +from Orange.data import Table, Domain, ContinuousVariable +from Orange.evaluation import CrossValidation, CA, RMSE +from Orange.tests import test_filename + + +class TestSVMLearner(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.data = Table(test_filename('datasets/ionosphere.tab')) + cls.data.shuffle() + + def test_SVM(self): + learn = SVMLearner() + cv = CrossValidation(k=2) + res = cv(self.data, [learn]) + self.assertGreater(CA(res)[0], 0.9) + + def test_LinearSVM(self): + # This warning is irrelevant here + warnings.filterwarnings("ignore", ".*", ConvergenceWarning) + learn = LinearSVMLearner() + cv = CrossValidation(k=2) + res = cv(self.data, [learn]) + self.assertGreater(CA(res)[0], 0.8) + self.assertLess(CA(res)[0], 0.9) + + def test_NuSVM(self): + learn = NuSVMLearner(nu=0.01) + cv = CrossValidation(k=2) + res = cv(self.data, [learn]) + self.assertGreater(CA(res)[0], 0.9) + + def test_SVR(self): + nrows, ncols = 200, 5 + X = np.random.rand(nrows, ncols) + y = X.dot(np.random.rand(ncols)) + data = Table.from_numpy(None, X, y) + learn = SVRLearner(kernel='rbf', gamma=0.1) + cv = CrossValidation(k=2) + res = cv(data, [learn]) + self.assertLess(RMSE(res)[0], 0.15) + + def test_LinearSVR(self): + nrows, ncols = 200, 5 + X = np.random.rand(nrows, ncols) + y = X.dot(np.random.rand(ncols)) + data = Table.from_numpy(None, X, y) + learn = SVRLearner() + cv = CrossValidation(k=2) + res = cv(data, [learn]) + self.assertLess(RMSE(res)[0], 0.15) + + def test_NuSVR(self): + nrows, ncols = 200, 5 + X = np.random.rand(nrows, ncols) + y = X.dot(np.random.rand(ncols)) + data = Table.from_numpy(None, X, y) + learn = NuSVRLearner(kernel='rbf', gamma=0.1) + cv = CrossValidation(k=2) + res = cv(data, [learn]) + self.assertLess(RMSE(res)[0], 0.1) + + def test_OneClassSVM(self): + np.random.seed(42) + domain = Domain((ContinuousVariable("c1"), ContinuousVariable("c2"))) + X_in = 0.3 * np.random.randn(40, 2) + X_out = np.random.uniform(low=-4, high=4, size=(20, 2)) + X_all = Table(domain, np.r_[X_in + 2, X_in - 2, X_out]) + n_true_in = len(X_in) * 2 + n_true_out = len(X_out) + + nu = 0.2 + learner = OneClassSVMLearner(nu=nu) + cls = learner(X_all) + y_pred = cls(X_all) + n_pred_out_all = np.sum(y_pred == -1) + n_pred_in_true_in = np.sum(y_pred[:n_true_in] == 1) + n_pred_out_true_out = np.sum(y_pred[- n_true_out:] == -1) + + self.assertEqual(np.absolute(y_pred).all(), 1) + self.assertLessEqual(n_pred_out_all, len(X_all) * nu) + self.assertLess(np.absolute(n_pred_out_all - n_true_out), 2) + self.assertLess(np.absolute(n_pred_in_true_in - n_true_in), 4) + self.assertLess(np.absolute(n_pred_out_true_out - n_true_out), 3) + + def test_OneClassSVM_ignores_y(self): + domain = Domain((ContinuousVariable("x1"), ContinuousVariable("x2")), + class_vars=(ContinuousVariable("y1"), ContinuousVariable("y2"))) + X = np.random.random((40, 2)) + Y = np.random.random((40, 2)) + table = Table(domain, X, Y) + classless_table = table.transform(Domain(table.domain.attributes)) + learner = OneClassSVMLearner() + classless_model = learner(classless_table) + model = learner(table) + pred1 = classless_model(classless_table) + pred2 = classless_model(table) + pred3 = model(classless_table) + pred4 = model(table) + + np.testing.assert_array_equal(pred1, pred2) + np.testing.assert_array_equal(pred2, pred3) + np.testing.assert_array_equal(pred3, pred4) diff --git a/pyminer2/tests/test_tab_reader.py b/pyminer2/tests/test_tab_reader.py new file mode 100644 index 0000000000000000000000000000000000000000..2659753ac6b1effa89b4d1c77761c49bb813d185 --- /dev/null +++ b/pyminer2/tests/test_tab_reader.py @@ -0,0 +1,284 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import io +from os import path, remove +import unittest +import tempfile +import shutil +import time +from collections import OrderedDict + +import numpy as np + +from Orange.data import Table, DiscreteVariable +from Orange.data.io import TabReader + + +def read_tab_file(filename): + return TabReader(filename).read() + + +class TestTabReader(unittest.TestCase): + + def setUp(self): + self.data = Table.from_numpy(None, [[1, 2, 3]]) + + def test_read_easy(self): + simplefile = """\ + Feature 1\tFeature 2\tClass 1\tClass 42 + d \tM F \td \td + \t \tclass \tclass + 1.0 \tM \t5 \trich + \tF \t7 \tpoor + 2.0 \tM \t4 \t + """ + + file = io.StringIO(simplefile) + table = read_tab_file(file) + + f1, f2, c1, c2 = table.domain.variables + self.assertIsInstance(f1, DiscreteVariable) + self.assertEqual(f1.name, "Feature 1") + self.assertIsInstance(f2, DiscreteVariable) + self.assertEqual(f2.name, "Feature 2") + self.assertIsInstance(c1, DiscreteVariable) + self.assertEqual(c1.name, "Class 1") + self.assertIsInstance(c2, DiscreteVariable) + self.assertEqual(c2.name, "Class 42") + + np.testing.assert_almost_equal(table.X, np.array([[0, 0], [np.nan, 1], [1, 0]])) + np.testing.assert_almost_equal(table.Y, np.array([[1, 1], [2, 0], [0, np.nan]])) + + def test_read_save_quoted(self): + quoted = '''\ + S\tA + s\td + m\t + """a"""\ti + """b"""\tj + """c\td"""\tk + ''' + expected = ['"a"', '"b"', '"c\td"'] + f = io.StringIO(quoted) + table = read_tab_file(f) + self.assertSequenceEqual(table.metas[:, 0].tolist(), expected) + + f = io.StringIO() + f.close = lambda: None + TabReader.write_file(f, table) + saved = f.getvalue() + table1 = read_tab_file(io.StringIO(saved)) + self.assertSequenceEqual(table1.metas[:, 0].tolist(), expected) + + def test_read_and_save_attributes(self): + samplefile = """\ + Feature 1\tFeature 2\tClass 1\tClass 42 + d \tM F \td \td + \ta=1 b=2 \tclass x=a\\ longer\\ string \tclass + 1.0 \tM \t5 \trich + """ + file = io.StringIO(samplefile) + table = read_tab_file(file) + + f1, f2, c1, c2 = table.domain.variables + self.assertIsInstance(f2, DiscreteVariable) + self.assertEqual(f2.name, "Feature 2") + self.assertEqual(f2.attributes, {'a': 1, 'b': 2}) + self.assertIn(c1, table.domain.class_vars) + self.assertIsInstance(c1, DiscreteVariable) + self.assertEqual(c1.name, "Class 1") + self.assertEqual(c1.attributes, {'x': 'a longer string'}) + outf = io.StringIO() + outf.close = lambda: None + TabReader.write_file(outf, table) + saved = outf.getvalue() + + file = io.StringIO(saved) + table = read_tab_file(file) + + f1, f2, c1, c2 = table.domain.variables + self.assertIsInstance(f2, DiscreteVariable) + self.assertEqual(f2.name, "Feature 2") + self.assertEqual(f2.attributes, {'a': 1, 'b': 2}) + self.assertIn(c1, table.domain.class_vars) + self.assertIsInstance(c1, DiscreteVariable) + self.assertEqual(c1.name, "Class 1") + self.assertEqual(c1.attributes, {'x': 'a longer string'}) + + path = "/path/to/somewhere" + c1.attributes["path"] = path + outf = io.StringIO() + outf.close = lambda: None + TabReader.write_file(outf, table) + outf.seek(0) + + table = read_tab_file(outf) + f1, f2, c1, c2 = table.domain.variables + self.assertEqual(c1.attributes["path"], path) + + def test_read_data_oneline_header(self): + samplefile = """\ + data1\tdata2\tdata3 + 0.1\t0.2\t0.3 + 1.1\t1.2\t1.5 + """ + file = io.StringIO(samplefile) + table = read_tab_file(file) + + self.assertEqual(len(table), 2) + self.assertEqual(len(table.domain), 3) + self.assertEqual(table.domain[0].name, 'data1') + + def test_read_data_no_header(self): + samplefile = """\ + 0.1\t0.2\t0.3 + 1.1\t1.2\t1.5 + """ + file = io.StringIO(samplefile) + table = read_tab_file(file) + + self.assertEqual(len(table), 2) + self.assertEqual(len(table.domain), 3) + self.assertTrue(table.domain[0].is_continuous) + self.assertEqual(table.domain[0].name, 'Feature 1') + + def test_read_data_no_header_feature_reuse(self): + samplefile = """\ + 0.1\t0.2\t0.3 + 1.1\t1.2\t1.5 + """ + file = io.StringIO(samplefile) + t1 = read_tab_file(file) + file = io.StringIO(samplefile) + t2 = read_tab_file(file) + self.assertEqual(t1.domain[0], t2.domain[0]) + + def test_renaming(self): + simplefile = """\ + a\t b\t a\t a\t b\t a\t c\t a\t b + c\t c\t c\t c\t c\t c\t c\t c\t c + \t \t \t \t class\t class\t \t \t meta + 0\t 0\t 0\t 0\t 0\t 0\t 0\t 0 """ + file = tempfile.NamedTemporaryFile("wt", delete=False, suffix=".tab") + filename = file.name + try: + file.write(simplefile) + file.close() + table = read_tab_file(filename) + domain = table.domain + self.assertEqual([x.name for x in domain.attributes], + ["a_1", "b_1", "a_2", "a_3", "c", "a_5"]) + self.assertEqual([x.name for x in domain.class_vars], ["b_2", "a_4"]) + self.assertEqual([x.name for x in domain.metas], ["b_3"]) + finally: + remove(filename) + + + def test_dataset_with_weird_names_and_column_attributes(self): + data = Table(path.join(path.dirname(__file__), 'datasets/weird.tab')) + self.assertEqual(len(data), 6) + self.assertEqual(len(data.domain), 1) + self.assertEqual(len(data.domain.metas), 1) + NAME = ['5534fab7fad58d5df50061f1', '5534fab8fad58d5de20061f8'] + self.assertEqual(data.domain[0].name, str(NAME)) + ATTRIBUTES = dict( + Timepoint=20, + id=NAME, + Name=['Gene expressions (dd_AX4_on_Ka_20Hr_bio1_mapped.bam)', + 'Gene expressions (dd_AX4_on_Ka_20Hr_bio2_mapped.bam)'], + Replicate=['1', '2'], + ) + self.assertEqual(data.domain[0].attributes, ATTRIBUTES) + + def test_sheets(self): + file1 = io.StringIO("\n".join("xd dbac")) + reader = TabReader(file1) + + self.assertEqual(reader.sheets, []) + + def test_attributes_saving(self): + tempdir = tempfile.mkdtemp() + try: + self.assertEqual(self.data.attributes, {}) + self.data.attributes[1] = "test" + self.data.save(path.join(tempdir, "out.tab")) + table = Table(path.join(tempdir, "out.tab")) + self.assertEqual(table.attributes[1], "test") + finally: + shutil.rmtree(tempdir) + + def test_attributes_saving_as_txt(self): + tempdir = tempfile.mkdtemp() + try: + self.data.attributes = OrderedDict() + self.data.attributes["a"] = "aa" + self.data.attributes["b"] = "bb" + self.data.save(path.join(tempdir, "out.tab")) + table = Table(path.join(tempdir, "out.tab")) + self.assertIsInstance(table.attributes, OrderedDict) + self.assertEqual(table.attributes["a"], "aa") + self.assertEqual(table.attributes["b"], "bb") + finally: + shutil.rmtree(tempdir) + + def test_data_name(self): + table1 = Table('iris') + table2 = TabReader(table1.__file__).read() + self.assertEqual(table1.name, 'iris') + self.assertEqual(table2.name, 'iris') + + def test_metadata(self): + tempdir = tempfile.mkdtemp() + try: + self.data.attributes = OrderedDict() + self.data.attributes["a"] = "aa" + self.data.attributes["b"] = "bb" + fname = path.join(tempdir, "out.tab") + TabReader.write_table_metadata(fname, self.data) + self.assertTrue(path.isfile(fname + ".metadata")) + finally: + shutil.rmtree(tempdir) + + def test_no_metadata(self): + tempdir = tempfile.mkdtemp() + try: + self.data.attributes = OrderedDict() + fname = path.join(tempdir, "out.tab") + TabReader.write_table_metadata(fname, self.data) + self.assertFalse(path.isfile(fname + ".metadata")) + finally: + shutil.rmtree(tempdir) + + def test_had_metadata_now_there_is_none(self): + tempdir = tempfile.mkdtemp() + try: + self.data.attributes["a"] = "aa" + fname = path.join(tempdir, "out.tab") + TabReader.write_table_metadata(fname, self.data) + self.assertTrue(path.isfile(fname + ".metadata")) + del self.data.attributes["a"] + TabReader.write_table_metadata(fname, self.data) + self.assertFalse(path.isfile(fname + ".metadata")) + finally: + shutil.rmtree(tempdir) + + def test_number_of_decimals(self): + data = Table("heart_disease") + self.assertEqual(data.domain["age"].number_of_decimals, 0) + self.assertEqual(data.domain["ST by exercise"].number_of_decimals, 1) + + data = Table("housing") + self.assertEqual(data.domain["CRIM"].number_of_decimals, 5) + self.assertEqual(data.domain["INDUS"].number_of_decimals, 2) + self.assertEqual(data.domain["AGE"].number_of_decimals, 1) + + def test_many_discrete(self): + b = io.StringIO() + b.write("Poser\nd\n\n") + b.writelines("K" + str(i) + "\n" for i in range(30000)) + start = time.time() + _ = TabReader(b).read() + elapsed = time.time() - start + if elapsed > 2: + raise AssertionError() diff --git a/pyminer2/tests/test_table.py b/pyminer2/tests/test_table.py new file mode 100644 index 0000000000000000000000000000000000000000..cbe29bb5b7596a99865a0126c14a1cdb8f919c45 --- /dev/null +++ b/pyminer2/tests/test_table.py @@ -0,0 +1,2665 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import copy +import os +import random +import unittest +from unittest.mock import Mock, MagicMock, patch +from itertools import chain +from math import isnan + +import numpy as np +import scipy.sparse as sp + +from Orange import data +from Orange.data import (filter, Unknown, Variable, Table, DiscreteVariable, + ContinuousVariable, Domain, StringVariable) +from Orange.tests import test_dirname +from Orange.data.table import _optimize_indices + + +class TableTestCase(unittest.TestCase): + def setUp(self): + data.table.dataset_dirs.append(test_dirname()) + + def tearDown(self): + data.table.dataset_dirs.remove(test_dirname()) + + def test_indexing_class(self): + d = data.Table("datasets/test1") + self.assertEqual([e.get_class() for e in d], ["t", "t", "f"]) + cind = len(d.domain) - 1 + self.assertEqual([e[cind] for e in d], ["t", "t", "f"]) + self.assertEqual([e["d"] for e in d], ["t", "t", "f"]) + cvar = d.domain.class_var + self.assertEqual([e[cvar] for e in d], ["t", "t", "f"]) + + def test_filename(self): + dir = data.table.get_sample_datasets_dir() + d = data.Table("iris") + self.assertEqual(d.__file__, os.path.join(dir, "iris.tab")) + + d = data.Table("datasets/test2.tab") + self.assertTrue(d.__file__.endswith("test2.tab")) # platform dependent + + def test_indexing(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + # regular, discrete + varc = d.domain["c"] + self.assertEqual(d[0, 1], "0") + self.assertEqual(d[0, varc], "0") + self.assertEqual(d[0, "c"], "0") + self.assertEqual(d[0][1], "0") + self.assertEqual(d[0][varc], "0") + self.assertEqual(d[0]["c"], "0") + self.assertEqual(d[np.int_(0), np.int_(1)], "0") + self.assertEqual(d[np.int_(0)][np.int_(1)], "0") + + # regular, continuous + varb = d.domain["b"] + self.assertEqual(d[0, 0], 0) + self.assertEqual(d[0, varb], 0) + self.assertEqual(d[0, "b"], 0) + self.assertEqual(d[0][0], 0) + self.assertEqual(d[0][varb], 0) + self.assertEqual(d[0]["b"], 0) + self.assertEqual(d[np.int_(0), np.int_(0)], 0) + self.assertEqual(d[np.int_(0)][np.int_(0)], 0) + + # negative + varb = d.domain["b"] + self.assertEqual(d[-2, 0], 3.333) + self.assertEqual(d[-2, varb], 3.333) + self.assertEqual(d[-2, "b"], 3.333) + self.assertEqual(d[-2][0], 3.333) + self.assertEqual(d[-2][varb], 3.333) + self.assertEqual(d[-2]["b"], 3.333) + self.assertEqual(d[np.int_(-2), np.int_(0)], 3.333) + self.assertEqual(d[np.int_(-2)][np.int_(0)], 3.333) + + # meta, discrete + vara = d.domain["a"] + metaa = d.domain.index("a") + self.assertEqual(d[0, metaa], "A") + self.assertEqual(d[0, vara], "A") + self.assertEqual(d[0, "a"], "A") + self.assertEqual(d[0][metaa], "A") + self.assertEqual(d[0][vara], "A") + self.assertEqual(d[0]["a"], "A") + self.assertEqual(d[np.int_(0), np.int_(metaa)], "A") + self.assertEqual(d[np.int_(0)][np.int_(metaa)], "A") + + # meta, string + vare = d.domain["e"] + metae = d.domain.index("e") + self.assertEqual(d[0, metae], "i") + self.assertEqual(d[0, vare], "i") + self.assertEqual(d[0, "e"], "i") + self.assertEqual(d[0][metae], "i") + self.assertEqual(d[0][vare], "i") + self.assertEqual(d[0]["e"], "i") + self.assertEqual(d[np.int_(0), np.int_(metae)], "i") + self.assertEqual(d[np.int_(0)][np.int_(metae)], "i") + + def test_indexing_example(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + e = d[0] + + # regular, discrete + varc = d.domain["c"] + self.assertEqual(e[1], "0") + self.assertEqual(e[varc], "0") + self.assertEqual(e["c"], "0") + self.assertEqual(e[np.int_(1)], "0") + + # regular, continuous + varb = d.domain["b"] + self.assertEqual(e[0], 0) + self.assertEqual(e[varb], 0) + self.assertEqual(e["b"], 0) + self.assertEqual(e[np.int_(0)], 0) + + # meta, discrete + vara = d.domain["a"] + metaa = d.domain.index("a") + self.assertEqual(e[metaa], "A") + self.assertEqual(e[vara], "A") + self.assertEqual(e["a"], "A") + self.assertEqual(e[np.int_(metaa)], "A") + + # meta, string + vare = d.domain["e"] + metae = d.domain.index("e") + self.assertEqual(e[metae], "i") + self.assertEqual(e[vare], "i") + self.assertEqual(e["e"], "i") + self.assertEqual(e[np.int_(metae)], "i") + + def test_indexing_assign_value(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + # meta + vara = d.domain["a"] + metaa = d.domain.index("a") + + self.assertEqual(d[0, "a"], "A") + d[0, "a"] = "B" + self.assertEqual(d[0, "a"], "B") + d[0]["a"] = "A" + self.assertEqual(d[0, "a"], "A") + + d[0, vara] = "B" + self.assertEqual(d[0, "a"], "B") + d[0][vara] = "A" + self.assertEqual(d[0, "a"], "A") + + d[0, metaa] = "B" + self.assertEqual(d[0, "a"], "B") + d[0][metaa] = "A" + self.assertEqual(d[0, "a"], "A") + + d[0, np.int_(metaa)] = "B" + self.assertEqual(d[0, "a"], "B") + d[0][np.int_(metaa)] = "A" + self.assertEqual(d[0, "a"], "A") + + # regular + varb = d.domain["b"] + + self.assertEqual(d[0, "b"], 0) + d[0, "b"] = 42 + self.assertEqual(d[0, "b"], 42) + d[0]["b"] = 0 + self.assertEqual(d[0, "b"], 0) + + d[0, varb] = 42 + self.assertEqual(d[0, "b"], 42) + d[0][varb] = 0 + self.assertEqual(d[0, "b"], 0) + + d[0, 0] = 42 + self.assertEqual(d[0, "b"], 42) + d[0][0] = 0 + self.assertEqual(d[0, "b"], 0) + + d[0, np.int_(0)] = 42 + self.assertEqual(d[0, "b"], 42) + d[0][np.int_(0)] = 0 + self.assertEqual(d[0, "b"], 0) + + def test_indexing_assign_example(self): + def almost_equal_list(s, t): + for e, f in zip(s, t): + self.assertAlmostEqual(e, f) + + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + self.assertFalse(isnan(d[0, "a"])) + d[0] = ["3.14", "1", "f"] + almost_equal_list(d[0].values(), [3.14, "1", "f"]) + self.assertTrue(isnan(d[0, "a"])) + d[0] = [3.15, 1, "t"] + almost_equal_list(d[0].values(), [3.15, "0", "t"]) + d[np.int_(0)] = [3.15, 2, "f"] + almost_equal_list(d[0].values(), [3.15, 2, "f"]) + + with self.assertRaises(ValueError): + d[0] = ["3.14", "1"] + + with self.assertRaises(ValueError): + d[np.int_(0)] = ["3.14", "1"] + + ex = data.Instance(d.domain, ["3.16", "1", "f"]) + d[0] = ex + almost_equal_list(d[0].values(), [3.16, "1", "f"]) + + ex = data.Instance(d.domain, ["3.16", 2, "t"]) + d[np.int_(0)] = ex + almost_equal_list(d[0].values(), [3.16, 2, "t"]) + + ex = data.Instance(d.domain, ["3.16", "1", "f"]) + ex["e"] = "mmmapp" + d[0] = ex + almost_equal_list(d[0].values(), [3.16, "1", "f"]) + self.assertEqual(d[0, "e"], "mmmapp") + + def test_slice(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + x = d[:3] + self.assertEqual(len(x), 3) + self.assertEqual([e[0] for e in x], [0, 1.1, 2.22]) + + x = d[2:5] + self.assertEqual(len(x), 3) + self.assertEqual([e[0] for e in x], [2.22, 2.23, 2.24]) + + x = d[4:1:-1] + self.assertEqual(len(x), 3) + self.assertEqual([e[0] for e in x], [2.24, 2.23, 2.22]) + + x = d[-3:] + self.assertEqual(len(x), 3) + self.assertEqual([e[0] for e in x], [2.26, 3.333, Unknown]) + + def test_assign_slice_value(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + d[2:5, 0] = 42 + self.assertEqual([e[0] for e in d], + [0, 1.1, 42, 42, 42, 2.25, 2.26, 3.333, Unknown]) + d[:3, "b"] = 43 + self.assertEqual([e[0] for e in d], + [43, 43, 43, 42, 42, 2.25, 2.26, 3.333, None]) + d[-2:, d.domain[0]] = 44 + self.assertEqual([e[0] for e in d], + [43, 43, 43, 42, 42, 2.25, 2.26, 44, 44]) + + d[2:5, "a"] = "A" + self.assertEqual([e["a"] for e in d], list("ABAAACCDE")) + + def test_multiple_indices(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + with self.assertRaises(IndexError): + x = d[2, 5, 1] + + with self.assertRaises(IndexError): + x = d[(2, 5, 1)] + + x = d[[2, 5, 1]] + self.assertEqual([e[0] for e in x], [2.22, 2.25, 1.1]) + + def test_assign_multiple_indices_value(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + d[1:4, "b"] = 42 + self.assertEqual([e[0] for e in d], + [0, 42, 42, 42, 2.24, 2.25, 2.26, 3.333, None]) + + d[range(5, 2, -1), "b"] = None + self.assertEqual([e[d.domain[0]] for e in d], + [0, 42, 42, None, "?", "", 2.26, 3.333, None]) + + def test_set_multiple_indices_example(self): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + d = data.Table("datasets/test2") + + vals = [e[0] for e in d] + d[[1, 2, 5]] = [42, None, None] + vals[1] = vals[2] = vals[5] = 42 + self.assertEqual([e[0] for e in d], vals) + + def test_bool(self): + d = data.Table("iris") + self.assertTrue(d) + + d = data.Table("datasets/test3") + self.assertFalse(d) + + d = data.Table("iris") + self.assertTrue(d) + + def test_checksum(self): + d = data.Table("zoo") + d[42, 3] = 0 + crc1 = d.checksum(False) + d[42, 3] = 1 + crc2 = d.checksum(False) + self.assertNotEqual(crc1, crc2) + d[42, 3] = 0 + crc3 = d.checksum(False) + self.assertEqual(crc1, crc3) + _ = d[42, "name"] + d[42, "name"] = "non-animal" + crc4 = d.checksum(False) + self.assertEqual(crc1, crc4) + crc4 = d.checksum(True) + crc5 = d.checksum(1) + crc6 = d.checksum(False) + self.assertNotEqual(crc1, crc4) + self.assertNotEqual(crc1, crc5) + self.assertEqual(crc1, crc6) + + def test_total_weight(self): + d = data.Table("zoo") + self.assertEqual(d.total_weight(), len(d)) + + d.set_weights(0) + d[0].weight = 0.1 + d[10].weight = 0.2 + d[-1].weight = 0.3 + self.assertAlmostEqual(d.total_weight(), 0.6) + + def test_has_missing(self): + d = data.Table("zoo") + self.assertFalse(d.has_missing()) + self.assertFalse(d.has_missing_class()) + + d[10, 3] = "?" + self.assertTrue(d.has_missing()) + self.assertFalse(d.has_missing_class()) + + d[10].set_class("?") + self.assertTrue(d.has_missing()) + self.assertTrue(d.has_missing_class()) + + d = data.Table("datasets/test3") + self.assertFalse(d.has_missing()) + self.assertFalse(d.has_missing_class()) + + def test_shuffle(self): + d = data.Table("zoo") + crc = d.checksum() + names = set(str(x["name"]) for x in d) + + d.shuffle() + self.assertNotEqual(crc, d.checksum()) + self.assertSetEqual(names, set(str(x["name"]) for x in d)) + crc2 = d.checksum() + + x = d[2:10] + crcx = x.checksum() + d.shuffle() + self.assertNotEqual(crc2, d.checksum()) + self.assertEqual(crcx, x.checksum()) + + crc2 = d.checksum() + x.shuffle() + self.assertNotEqual(crcx, x.checksum()) + self.assertEqual(crc2, d.checksum()) + + @staticmethod + def not_less_ex(ex1, ex2): + for v1, v2 in zip(ex1, ex2): + if v1 != v2: + return v1 < v2 + return True + + @staticmethod + def sorted(d): + for i in range(1, len(d)): + if not TableTestCase.not_less_ex(d[i - 1], d[i]): + return False + return True + + @staticmethod + def not_less_ex_ord(ex1, ex2, ord): + for a in ord: + if ex1[a] != ex2[a]: + return ex1[a] < ex2[a] + return True + + @staticmethod + def sorted_ord(d, ord): + for i in range(1, len(d)): + if not TableTestCase.not_less_ex_ord(d[i - 1], d[i], ord): + return False + return True + + def test_copy(self): + t = data.Table.from_numpy( + None, np.zeros((5, 3)), np.arange(5), np.zeros((5, 3))) + + copy = t.copy() + self.assertTrue(np.all(t.X == copy.X)) + self.assertTrue(np.all(t.Y == copy.Y)) + self.assertTrue(np.all(t.metas == copy.metas)) + copy[0] = [1, 1, 1, 1, 1, 1, 1, 1] + self.assertFalse(np.all(t.X == copy.X)) + self.assertFalse(np.all(t.Y == copy.Y)) + self.assertFalse(np.all(t.metas == copy.metas)) + + def test_copy_sparse(self): + t = data.Table('iris').to_sparse() + copy = t.copy() + + self.assertEqual((t.X != copy.X).nnz, 0) # sparse matrices match by content + np.testing.assert_equal(t.Y, copy.Y) + np.testing.assert_equal(t.metas, copy.metas) + + self.assertNotEqual(id(t.X), id(copy.X)) + self.assertNotEqual(id(t._Y), id(copy._Y)) + self.assertNotEqual(id(t.metas), id(copy.metas)) + + def test_concatenate(self): + d1 = data.Domain( + [data.ContinuousVariable(n) for n in "abc"], + data.DiscreteVariable("y", values="ABC"), + [data.StringVariable(n) for n in ["m1", "m2"]], + ) + x1 = np.arange(6).reshape(2, 3) + y1 = np.array([0, 1]) + m1 = np.array([["foo", "bar"], ["baz", "qux"]]) + w1 = np.random.random((2,)) + t1 = data.Table.from_numpy(d1, x1, y1, m1, w1) + t1.ids = ids1 = np.array([100, 101]) + t1.attributes = {"a": 42, "c": 43} + + x2 = np.arange(6, 15).reshape(3, 3) + y2 = np.array([1, 2, 0]) + m2 = np.array([["a", "b"], ["c", "d"], ["e", "f"]]) + w2 = np.random.random((3,)) + t2 = data.Table.from_numpy(d1, x2, y2, m2, w2) + t2.ids = ids2 = np.array([102, 103, 104]) + t2.name = "t2" + t2.attributes = {"a": 44, "b": 45} + + x3 = np.arange(15, 27).reshape(4, 3) + y3 = np.array([2, 1, 1, 0]) + m3 = np.array([["g", "h"], ["i", "j"], ["k", "l"], ["m", "n"]]) + w3 = np.random.random((4,)) + t3 = data.Table.from_numpy(d1, x3, y3, m3, w3) + t3.ids = ids3 = np.array([102, 103, 104, 105]) + t3.name = "t3" + + t1b = data.Table.concatenate((t1,)) + self.assertEqual(t1b.domain, t1.domain) + np.testing.assert_almost_equal(t1b.X, x1) + np.testing.assert_almost_equal(t1b.Y, y1) + self.assertEqual(list(t1b.metas.flatten()), + list(m1.flatten())) + np.testing.assert_almost_equal(t1b.W, w1) + np.testing.assert_almost_equal(t1b.ids, ids1) + self.assertEqual(t1b.name, t1.name) + self.assertEqual(t1b.attributes, {"a": 42, "c": 43}) + + t12 = data.Table.concatenate((t1, t2)) + self.assertEqual(t12.domain, t1.domain) + np.testing.assert_almost_equal(t12.X, np.vstack((x1, x2))) + np.testing.assert_almost_equal(t12.Y, np.hstack((y1, y2))) + self.assertEqual(list(t12.metas.flatten()), + list(np.vstack((m1, m2)).flatten())) + np.testing.assert_almost_equal(t12.W, np.hstack((w1, w2))) + np.testing.assert_almost_equal(t12.ids, np.hstack((ids1, ids2))) + self.assertEqual(t12.name, "t2") + self.assertEqual(t12.attributes, {"a": 42, "c": 43, "b": 45}) + + t123 = data.Table.concatenate((t1, t2, t3)) + self.assertEqual(t123.domain, t1.domain) + np.testing.assert_almost_equal(t123.X, np.vstack((x1, x2, x3))) + np.testing.assert_almost_equal(t123.Y, np.hstack((y1, y2, y3))) + self.assertEqual(list(t123.metas.flatten()), + list(np.vstack((m1, m2, m3)).flatten())) + np.testing.assert_almost_equal(t123.W, np.hstack((w1, w2, w3))) + np.testing.assert_almost_equal(t123.ids, np.hstack((ids1, ids2, ids3))) + self.assertEqual(t123.name, "t2") + self.assertEqual(t123.attributes, {"a": 42, "c": 43, "b": 45}) + + t2.Y = np.atleast_2d(t2.Y).T + t12 = data.Table.concatenate((t1, t2)) + self.assertEqual(t12.domain, t1.domain) + np.testing.assert_almost_equal(t12.X, np.vstack((x1, x2))) + np.testing.assert_almost_equal(t12.Y, np.hstack((y1, y2))) + self.assertEqual(list(t12.metas.flatten()), + list(np.vstack((m1, m2)).flatten())) + np.testing.assert_almost_equal(t12.W, np.hstack((w1, w2))) + np.testing.assert_almost_equal(t12.ids, np.hstack((ids1, ids2))) + self.assertEqual(t12.name, "t2") + self.assertEqual(t12.attributes, {"a": 42, "c": 43, "b": 45}) + + def test_concatenate_exceptions(self): + zoo = data.Table("zoo") + iris = data.Table("iris") + + self.assertRaises(ValueError, data.Table.concatenate, []) + self.assertRaises(ValueError, data.Table.concatenate, [zoo], axis=1) + self.assertRaises(ValueError, data.Table.concatenate, [zoo, iris]) + + def test_concatenate_sparse(self): + iris = Table("iris") + iris.X = sp.csc_matrix(iris.X) + new = Table.concatenate([iris, iris]) + self.assertEqual(len(new), 300) + self.assertTrue(sp.issparse(new.X), "Concatenated X is not sparse.") + self.assertFalse(sp.issparse(new.Y), "Concatenated Y is not dense.") + self.assertFalse(sp.issparse(new.metas), "Concatenated metas is not dense.") + self.assertEqual(len(new.ids), 300) + + def test_pickle(self): + import pickle + + d = data.Table("zoo") + s = pickle.dumps(d) + d2 = pickle.loads(s) + self.assertEqual(d[0], d2[0]) + + self.assertEqual(d.checksum(include_metas=False), + d2.checksum(include_metas=False)) + + d = data.Table("iris") + s = pickle.dumps(d) + d2 = pickle.loads(s) + self.assertEqual(d[0], d2[0]) + self.assertEqual(d.checksum(include_metas=False), + d2.checksum(include_metas=False)) + + def test_translate_through_slice(self): + d = data.Table("iris") + dom = data.Domain(["petal length", "sepal length", "iris"], + source=d.domain) + d_ref = d[:10, dom.variables] + self.assertEqual(d_ref.domain.class_var, d.domain.class_var) + self.assertEqual(d_ref[0, "petal length"], d[0, "petal length"]) + self.assertEqual(d_ref[0, "sepal length"], d[0, "sepal length"]) + self.assertEqual(d_ref.X.shape, (10, 2)) + self.assertEqual(d_ref.Y.shape, (10,)) + + def test_saveTab(self): + d = data.Table("iris")[:3] + d.save("test-save.tab") + try: + d2 = data.Table("test-save.tab") + for e1, e2 in zip(d, d2): + self.assertEqual(e1, e2) + finally: + os.remove("test-save.tab") + os.remove("test-save.tab.metadata") + + dom = data.Domain([data.ContinuousVariable("a")]) + d = data.Table.from_list(dom, [[i] for i in range(3)]) + d.save("test-save.tab") + try: + d2 = data.Table("test-save.tab") + self.assertEqual(len(d.domain.attributes), 1) + self.assertEqual(d.domain.class_var, None) + for i in range(3): + self.assertEqual(d2[i], [i]) + finally: + os.remove("test-save.tab") + + dom = data.Domain([data.ContinuousVariable("a")], None) + d = data.Table.from_list(dom, [[i] for i in range(3)]) + d.save("test-save.tab") + try: + d2 = data.Table("test-save.tab") + self.assertEqual(len(d.domain.attributes), 1) + for i in range(3): + self.assertEqual(d2[i], [i]) + finally: + os.remove("test-save.tab") + + d = data.Table("zoo") + d.save("test-zoo.tab") + dd = data.Table("test-zoo") + try: + self.assertTupleEqual(d.domain.metas, dd.domain.metas, + msg="Meta attributes don't match.") + self.assertTupleEqual(d.domain.variables, dd.domain.variables, + msg="Attributes don't match.") + + np.testing.assert_almost_equal(d.W, dd.W, + err_msg="Weights don't match.") + for i in range(10): + for j in d.domain.variables: + self.assertEqual(d[i][j], dd[i][j]) + finally: + os.remove("test-zoo.tab") + os.remove("test-zoo.tab.metadata") + + d = data.Table("zoo") + d.set_weights(range(len(d))) + d.save("test-zoo-weights.tab") + dd = data.Table("test-zoo-weights") + try: + self.assertTupleEqual(d.domain.metas, dd.domain.metas, + msg="Meta attributes don't match.") + self.assertTupleEqual(d.domain.variables, dd.domain.variables, + msg="Attributes don't match.") + + np.testing.assert_almost_equal(d.W, dd.W, + err_msg="Weights don't match.") + for i in range(10): + for j in d.domain.variables: + self.assertEqual(d[i][j], dd[i][j]) + finally: + os.remove("test-zoo-weights.tab") + os.remove("test-zoo-weights.tab.metadata") + + def test_save_pickle(self): + table = data.Table("iris") + try: + table.save("iris.pickle") + table2 = data.Table.from_file("iris.pickle") + np.testing.assert_almost_equal(table.X, table2.X) + np.testing.assert_almost_equal(table.Y, table2.Y) + self.assertEqual(table.domain[0], table2.domain[0]) + finally: + os.remove("iris.pickle") + + def test_from_numpy(self): + a = np.arange(20, dtype="d").reshape((4, 5)) + a[:, -1] = [0, 0, 0, 1] + dom = data.Domain([data.ContinuousVariable(x) for x in "abcd"], + data.DiscreteVariable("e", values=["no", "yes"])) + table = data.Table(dom, a) + for i in range(4): + self.assertEqual(table[i].get_class(), "no" if i < 3 else "yes") + for j in range(5): + self.assertEqual(a[i, j], table[i, j]) + table[i, j] = random.random() + self.assertEqual(a[i, j], table[i, j]) + + with self.assertRaises(IndexError): + table[0, -5] = 5 + + def test_filter_is_defined(self): + d = data.Table("iris") + d[1, 4] = Unknown + self.assertTrue(isnan(d[1, 4])) + d[140, 0] = Unknown + e = filter.IsDefined()(d) + self.assertEqual(len(e), len(d) - 2) + self.assertEqual(e[0], d[0]) + self.assertEqual(e[1], d[2]) + self.assertEqual(e[147], d[149]) + self.assertTrue(d.has_missing()) + self.assertFalse(e.has_missing()) + + def test_filter_has_class(self): + d = data.Table("iris") + d[1, 4] = Unknown + self.assertTrue(isnan(d[1, 4])) + d[140, 0] = Unknown + e = filter.HasClass()(d) + self.assertEqual(len(e), len(d) - 1) + self.assertEqual(e[0], d[0]) + self.assertEqual(e[1], d[2]) + self.assertEqual(e[148], d[149]) + self.assertTrue(d.has_missing()) + self.assertTrue(e.has_missing()) + self.assertFalse(e.has_missing_class()) + + def test_filter_random(self): + d = data.Table("iris") + e = filter.Random(50)(d) + self.assertEqual(len(e), 50) + e = filter.Random(50, negate=True)(d) + self.assertEqual(len(e), 100) + for _ in range(5): + e = filter.Random(0.2)(d) + self.assertEqual(len(e), 30) + bc = np.bincount(np.array(e.Y[:], dtype=int)) + if min(bc) > 7: + break + else: + self.fail("Filter returns too uneven distributions") + + def test_filter_values_nested(self): + d = data.Table("iris") + f1 = filter.FilterContinuous(d.columns.sepal_length, + filter.FilterContinuous.Between, + min=4.5, max=5.0) + f2 = filter.FilterContinuous(d.columns.sepal_width, + filter.FilterContinuous.Between, + min=3.1, max=3.4) + f3 = filter.FilterDiscrete(d.columns.iris, [0, 1]) + f = filter.Values([filter.Values([f1, f2], conjunction=False), f3]) + self.assertEqual(41, len(f(d))) + + def test_filter_string_works_for_numeric_columns(self): + var = StringVariable("s") + data = Table.from_list(Domain([], metas=[var]), + [[x] for x in range(21)]) + # 1, 2, 3, ..., 18, 19, 20 + + fs = filter.FilterString + filters = [ + ((fs.Greater, "5"), dict(rows=4)), + # 6, 7, 8, 9 + ((fs.Between, "15", "2"), dict(rows=6)), + # 15, 16, 17, 18, 19, 2 + ((fs.Contains, "2"), dict(rows=3)), + # 2, 12, 20 + ] + + for args, expected in filters: + f = fs(var, *args) + filtered_data = filter.Values([f])(data) + self.assertEqual(len(filtered_data), expected["rows"], + "{} returned wrong number of rows".format(args)) + + def test_filter_value_continuous(self): + d = data.Table("iris") + col = d.X[:, 2] + + v = d.columns + f = filter.FilterContinuous(v.petal_length, + filter.FilterContinuous.Between, + min=4.5, max=5.1) + + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] >= 4.5)) + self.assertTrue(np.all(x.X[:, 2] <= 5.1)) + self.assertEqual(sum((col >= 4.5) * (col <= 5.1)), len(x)) + + f.ref = 5.1 + f.oper = filter.FilterContinuous.Equal + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f.oper = filter.FilterContinuous.NotEqual + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] != 5.1)) + self.assertEqual(sum(col != 5.1), len(x)) + + f.oper = filter.FilterContinuous.Less + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] < 5.1)) + self.assertEqual(sum(col < 5.1), len(x)) + + f.oper = filter.FilterContinuous.LessEqual + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] <= 5.1)) + self.assertEqual(sum(col <= 5.1), len(x)) + + f.oper = filter.FilterContinuous.Greater + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] > 5.1)) + self.assertEqual(sum(col > 5.1), len(x)) + + f.oper = filter.FilterContinuous.GreaterEqual + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] >= 5.1)) + self.assertEqual(sum(col >= 5.1), len(x)) + + f.oper = filter.FilterContinuous.Outside + f.ref, f.max = 4.5, 5.1 + x = filter.Values([f])(d) + for e in x: + self.assertTrue(e[2] < 4.5 or e[2] > 5.1) + self.assertEqual(sum((col < 4.5) + (col > 5.1)), len(x)) + + f.oper = filter.FilterContinuous.IsDefined + f.ref = f.max = None + x = filter.Values([f])(d) + self.assertEqual(len(x), len(d)) + + d[:30, v.petal_length] = Unknown + x = filter.Values([f])(d) + self.assertEqual(len(x), len(d) - 30) + + def test_filter_value_continuous_args(self): + d = data.Table("iris") + col = d.X[:, 2] + v = d.columns + + f = filter.FilterContinuous(v.petal_length, + filter.FilterContinuous.Equal, ref=5.1) + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous(2, + filter.FilterContinuous.Equal, ref=5.1) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous("petal length", + filter.FilterContinuous.Equal, ref=5.1) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous("sepal length", + filter.FilterContinuous.Equal, ref=5.1) + f.column = 2 + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous("sepal length", + filter.FilterContinuous.Equal, ref=5.1) + f.column = v.petal_length + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous(v.petal_length, + filter.FilterContinuous.Equal, ref=18) + f.ref = 5.1 + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + f = filter.FilterContinuous(v.petal_length, + filter.FilterContinuous.Equal, ref=18) + f.ref = 5.1 + x = filter.Values([f])(d) + self.assertTrue(np.all(x.X[:, 2] == 5.1)) + self.assertEqual(sum(col == 5.1), len(x)) + + def test_valueFilter_discrete(self): + d = data.Table("zoo") + + f = filter.FilterDiscrete(d.domain.class_var, values=[2, 3, 4]) + for e in filter.Values([f])(d): + self.assertTrue(e.get_class() in [2, 3, 4]) + + f.values = ["mammal"] + for e in filter.Values([f])(d): + self.assertEqual(e.get_class(), "mammal") + + f = filter.FilterDiscrete(d.domain.class_var, values=[2, "mammal"]) + for e in filter.Values([f])(d): + self.assertTrue(e.get_class() in [2, "mammal"]) + + f = filter.FilterDiscrete(d.domain.class_var, values=[2, "martian"]) + self.assertRaises(ValueError, d._filter_values, f) + + f = filter.FilterDiscrete(d.domain.class_var, values=[2, data.Table]) + self.assertRaises(TypeError, d._filter_values, f) + + v = d.columns + f = filter.FilterDiscrete(v.hair, values=None) + self.assertEqual(len(filter.Values([f])(d)), len(d)) + + d[:5, v.hair] = Unknown + self.assertEqual(len(filter.Values([f])(d)), len(d) - 5) + + def test_valueFilter_string_is_defined(self): + d = data.Table("datasets/test9.tab") + f = filter.FilterString(-5, filter.FilterString.IsDefined) + x = filter.Values([f])(d) + self.assertEqual(len(x), 7) + + def test_valueFilter_discrete_meta_is_defined(self): + d = data.Table("datasets/test9.tab") + f = filter.FilterDiscrete(-4, None) + x = filter.Values([f])(d) + self.assertEqual(len(x), 8) + + def test_valueFilter_string_case_sens(self): + d = data.Table("zoo") + col = d[:, "name"].metas[:, 0] + + f = filter.FilterString("name", + filter.FilterString.Equal, "girl") + x = filter.Values([f])(d) + self.assertEqual(len(x), 1) + self.assertEqual(x[0, "name"], "girl") + self.assertTrue(np.all(x.metas == "girl")) + + f.oper = f.NotEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), len(d) - 1) + self.assertTrue(np.all(x[:, "name"] != "girl")) + + f.oper = f.Less + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col < "girl")) + self.assertTrue(np.all(x.metas < "girl")) + + f.oper = f.LessEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col <= "girl")) + self.assertTrue(np.all(x.metas <= "girl")) + + f.oper = f.Greater + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col > "girl")) + self.assertTrue(np.all(x.metas > "girl")) + + f.oper = f.GreaterEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col >= "girl")) + self.assertTrue(np.all(x.metas >= "girl")) + + f.oper = f.Between + f.max = "lion" + x = filter.Values([f])(d) + self.assertEqual(len(x), sum((col >= "girl") * (col <= "lion"))) + self.assertTrue(np.all(x.metas >= "girl")) + self.assertTrue(np.all(x.metas <= "lion")) + + f.oper = f.Outside + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col < "girl") + sum(col > "lion")) + self.assertTrue(np.all((x.metas < "girl") + (x.metas > "lion"))) + + f.oper = f.Contains + f.ref = "ea" + x = filter.Values([f])(d) + for e in x: + self.assertTrue("ea" in e["name"]) + self.assertEqual(len(x), len([e for e in col if "ea" in e])) + + f.oper = f.StartsWith + f.ref = "sea" + x = filter.Values([f])(d) + for e in x: + self.assertTrue(str(e["name"]).startswith("sea")) + self.assertEqual(len(x), len([e for e in col if e.startswith("sea")])) + + f.oper = f.EndsWith + f.ref = "ion" + x = filter.Values([f])(d) + for e in x: + self.assertTrue(str(e["name"]).endswith("ion")) + self.assertEqual(len(x), len([e for e in col if e.endswith("ion")])) + + def test_valueFilter_string_case_insens(self): + d = data.Table("zoo") + d[d[:, "name"].metas[:, 0] == "girl", "name"] = "GIrl" + + col = d[:, "name"].metas[:, 0] + + f = filter.FilterString("name", + filter.FilterString.Equal, "giRL") + f.case_sensitive = False + x = filter.Values([f])(d) + self.assertEqual(len(x), 1) + self.assertEqual(x[0, "name"], "GIrl") + self.assertTrue(np.all(x.metas == "GIrl")) + + f.oper = f.NotEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), len(d) - 1) + self.assertTrue(np.all(x[:, "name"] != "GIrl")) + + f.oper = f.Less + f.ref = "CHiCKEN" + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col < "chicken") - 1) # girl! + self.assertTrue(np.all(x.metas < "chicken")) + + f.oper = f.LessEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col <= "chicken") - 1) + self.assertTrue(np.all(x.metas <= "chicken")) + + f.oper = f.Greater + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col > "chicken") + 1) + for e in x: + self.assertGreater(str(e["name"]).lower(), "chicken") + + f.oper = f.GreaterEqual + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col >= "chicken") + 1) + for e in x: + self.assertGreaterEqual(str(e["name"]).lower(), "chicken") + + f.oper = f.Between + f.max = "liOn" + x = filter.Values([f])(d) + self.assertEqual(len(x), sum((col >= "chicken") * (col <= "lion")) + 1) + for e in x: + self.assertTrue("chicken" <= str(e["name"]).lower() <= "lion") + + f.oper = f.Outside + x = filter.Values([f])(d) + self.assertEqual(len(x), sum(col < "chicken") + sum(col > "lion") - 1) + self.assertTrue(np.all((x.metas < "chicken") + (x.metas > "lion"))) + + f.oper = f.Contains + f.ref = "iR" + x = filter.Values([f])(d) + for e in x: + self.assertTrue("ir" in str(e["name"]).lower()) + self.assertEqual(len(x), len([e for e in col if "ir" in e]) + 1) + + f.oper = f.StartsWith + f.ref = "GI" + x = filter.Values([f])(d) + for e in x: + self.assertTrue(str(e["name"]).lower().startswith("gi")) + self.assertEqual(len(x), + len([e for e in col if e.lower().startswith("gi")])) + + f.oper = f.EndsWith + f.ref = "ion" + x = filter.Values([f])(d) + for e in x: + self.assertTrue(str(e["name"]).endswith("ion")) + self.assertTrue(str(e["name"]).endswith("ion")) + self.assertEqual(len(x), len([e for e in col if e.endswith("ion")])) + + def test_valueFilter_regex(self): + d = data.Table("zoo") + f = filter.FilterRegex(d.domain['name'], '^c...$') + x = filter.Values([f])(d) + self.assertEqual(len(x), 7) + + def test_valueFilter_stringList(self): + data = Table("zoo") + var = data.domain["name"] + + fs = filter.FilterStringList + filters = [ + ((["swan", "tuna", "wasp"], True), dict(rows=3)), + ((["swan", "tuna", "wasp"], False), dict(rows=3)), + ((["WoRm", "TOad", "vOLe"], True), dict(rows=0)), + ((["WoRm", "TOad", "vOLe"], False), dict(rows=3)), + ] + + for args, expected in filters: + f = fs(var, *args) + filtered_data = filter.Values([f])(data) + self.assertEqual(len(filtered_data), expected["rows"], + "{} returned wrong number of rows".format(args)) + + def test_table_dtypes(self): + table = data.Table("iris") + metas = np.hstack((table.metas, table.Y.reshape(len(table), 1))) + attributes_metas = table.domain.metas + table.domain.class_vars + domain_metas = data.Domain(table.domain.attributes, + table.domain.class_vars, + attributes_metas) + table_metas = data.Table(domain_metas, table.X, table.Y, metas) + new_table = data.Table.from_table(data.Domain(table_metas.domain.metas, + table_metas.domain.metas, + table_metas.domain.metas), + table_metas) + self.assertEqual(new_table.X.dtype, np.float64) + self.assertEqual(new_table.Y.dtype, np.float64) + self.assertEqual(new_table.metas.dtype, np.float64) + + def test_attributes(self): + table = data.Table("iris") + table.attributes = {1: "test"} + table2 = table[:4] + self.assertEqual(table2.attributes[1], "test") + table2.attributes[1] = "modified" + self.assertEqual(table.attributes[1], "modified") + + # TODO Test conjunctions and disjunctions of conditions + + def test_is_sparse(self): + table = data.Table("iris") + self.assertFalse(table.is_sparse()) + + table.X = sp.csr_matrix(table.X) + self.assertTrue(table.is_sparse()) + + def test_repr_sparse_with_one_row(self): + table = data.Table("iris")[:1] + table.X = sp.csr_matrix(table.X) + repr(table) # make sure repr does not crash + + def test_inf(self): + a = np.array([[2, 0, 0, 0], + [0, np.nan, np.nan, 1], + [0, 0, np.inf, 0]]) + with self.assertWarns(Warning): + tab = data.Table.from_numpy(None, a) + self.assertEqual(tab.get_nan_frequency_attribute(), 3/12) + + +def column_sizes(table): + return (len(table.domain.attributes), + len(table.domain.class_vars), + len(table.domain.metas)) + + +class TableTests(unittest.TestCase): + attributes = ["Feature %i" % i for i in range(10)] + class_vars = ["Class %i" % i for i in range(1)] + metas = ["Meta %i" % i for i in range(5)] + nrows = 10 + row_indices = (1, 5, 7, 9) + + data = np.random.random((nrows, len(attributes))) + class_data = np.random.random((nrows, len(class_vars))) + meta_data = np.random.random((nrows, len(metas))) + weight_data = np.random.random((nrows, 1)) + + def setUp(self): + self.data = np.random.random((self.nrows, len(self.attributes))) + self.class_data = np.random.random((self.nrows, len(self.class_vars))) + if len(self.class_vars) == 1: + self.class_data = self.class_data.flatten() + self.meta_data = np.random.randint(0, 5, (self.nrows, len(self.metas)) + ).astype(object) + self.weight_data = np.random.random((self.nrows, 1)) + + def mock_domain(self, with_classes=False, with_metas=False): + attributes = self.attributes + class_vars = self.class_vars if with_classes else [] + metas = self.metas if with_metas else [] + variables = attributes + class_vars + return MagicMock(data.Domain, + attributes=attributes, + class_vars=class_vars, + metas=metas, + variables=variables) + + def create_domain(self, attributes=(), classes=(), metas=()): + attr_vars = [data.ContinuousVariable(name=a) if isinstance(a, str) + else a for a in attributes] + class_vars = [data.ContinuousVariable(name=c) if isinstance(c, str) + else c for c in classes] + meta_vars = [data.DiscreteVariable(name=m, values=map(str, range(5))) + if isinstance(m, str) else m for m in metas] + + domain = data.Domain(attr_vars, class_vars, meta_vars) + return domain + + +class CreateEmptyTable(TableTests): + def test_calling_new_with_no_parameters_constructs_a_new_instance(self): + table = data.Table() + self.assertIsInstance(table, data.Table) + + def test_table_has_file(self): + table = data.Table() + self.assertIsNone(table.__file__) + + +class CreateTableWithFilename(TableTests): + filename = "data.tab" + + @patch("os.path.exists", Mock(return_value=True)) + def test_read_data_calls_reader(self): + table_mock = Mock(data.Table) + reader_instance = Mock(read=Mock(return_value=table_mock)) + reader_mock = Mock(return_value=reader_instance) + + with patch.dict(data.io.FileFormat.readers, + {'.xlsx': reader_mock}): + table = data.Table.from_file("test.xlsx") + + reader_mock.assert_called_with("test.xlsx") + reader_instance.read.assert_called_with() + self.assertEqual(table, table_mock) + + @patch("os.path.exists", Mock(return_value=False)) + def test_raises_error_if_file_does_not_exist(self): + with self.assertRaises(IOError): + data.Table.from_file(self.filename) + + @patch("os.path.exists", Mock(return_value=True)) + def test_raises_error_if_file_has_unknown_extension(self): + with self.assertRaises(IOError): + data.Table.from_file("file.invalid_extension") + + @patch("Orange.data.table.Table.from_file") + def test_calling_new_with_string_argument_calls_read_data(self, read_data): + data.Table(self.filename) + + read_data.assert_called_with(self.filename) + + @patch("Orange.data.table.Table.from_file") + def test_calling_new_with_keyword_argument_filename_calls_read_data( + self, read_data): + data.Table(self.filename) + read_data.assert_called_with(self.filename) + + +class CreateTableWithUrl(TableTests): + def test_url_no_scheme(self): + + class SkipRest(Exception): + pass + + mock_urlopen = Mock(side_effect=SkipRest()) + url = 'www.foo.bar/xx.csv' + + with patch('Orange.data.io.UrlReader.urlopen', mock_urlopen): + try: + Table.from_url(url) + except SkipRest: + pass + + mock_urlopen.assert_called_once_with('http://' + url) + + class _MockUrlOpen(MagicMock): + headers = {'content-disposition': 'attachment; filename="Something-FormResponses.tsv"; ' + 'filename*=UTF-8''Something%20%28Responses%29.tsv'} + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + pass + + def read(self): + return b'''\ +a\tb\tc +1\t2\t3 +2\t3\t4''' + + urlopen = _MockUrlOpen() + + @patch('Orange.data.io.urlopen', urlopen) + def test_trimmed_urls(self): + for url in ('https://docs.google.com/spreadsheets/d/ABCD/edit', + 'https://www.dropbox.com/s/ABCD/filename.csv'): + self._MockUrlOpen.url = url + d = data.Table(url) + request = self.urlopen.call_args[0][0] + self.assertNotEqual(url, request.full_url) + self.assertIn('Mozilla/5.0', request.headers.get('User-agent', '')) + self.assertEqual(len(d), 2) + self.assertEqual(d.name, 'Something-FormResponses') + + +class CreateTableWithDomain(TableTests): + def test_creates_an_empty_table_with_given_domain(self): + domain = self.mock_domain() + table = data.Table.from_domain(domain) + + self.assertEqual(table.domain, domain) + + def test_creates_zero_filled_rows_in_X_if_domain_contains_attributes(self): + domain = self.mock_domain() + table = data.Table.from_domain(domain, self.nrows) + + self.assertEqual(table.X.shape, (self.nrows, len(domain.attributes))) + self.assertFalse(table.X.any()) + + def test_creates_zero_filled_rows_in_Y_if_domain_contains_class_vars(self): + domain = self.mock_domain(with_classes=True) + table = data.Table.from_domain(domain, self.nrows) + + if len(domain.class_vars) != 1: + self.assertEqual(table.Y.shape, + (self.nrows, len(domain.class_vars))) + else: + self.assertEqual(table.Y.shape, (self.nrows,)) + self.assertFalse(table.Y.any()) + + def test_creates_zero_filled_rows_in_metas_if_domain_contains_metas(self): + domain = self.mock_domain(with_metas=True) + table = data.Table.from_domain(domain, self.nrows) + + self.assertEqual(table.metas.shape, (self.nrows, len(domain.metas))) + self.assertFalse(table.metas.any()) + + def test_creates_weights_if_weights_are_true(self): + domain = self.mock_domain() + table = data.Table.from_domain(domain, self.nrows, True) + + self.assertEqual(table.W.shape, (self.nrows, )) + + def test_does_not_create_weights_if_weights_are_false(self): + domain = self.mock_domain() + table = data.Table.from_domain(domain, self.nrows, False) + + self.assertEqual(table.W.shape, (self.nrows, 0)) + + @patch("Orange.data.table.Table.from_domain") + def test_calling_new_with_domain_calls_new_from_domain( + self, new_from_domain): + domain = self.mock_domain() + data.Table.from_domain(domain) + + new_from_domain.assert_called_with(domain) + + +class CreateTableWithData(TableTests): + def test_creates_a_table_with_given_X(self): + # from numpy + table = data.Table.from_numpy(None, np.array(self.data)) + self.assertIsInstance(table.domain, data.Domain) + np.testing.assert_almost_equal(table.X, self.data) + + # from list + table = data.Table.from_numpy(None, list(self.data)) + self.assertIsInstance(table.domain, data.Domain) + np.testing.assert_almost_equal(table.X, self.data) + + # from tuple + table = data.Table.from_numpy(None, tuple(self.data)) + self.assertIsInstance(table.domain, data.Domain) + np.testing.assert_almost_equal(table.X, self.data) + + def test_creates_a_table_from_domain_and_list(self): + domain = data.Domain([data.DiscreteVariable(name="a", values="mf"), + data.ContinuousVariable(name="b")], + data.DiscreteVariable(name="y", values="abc")) + table = data.Table.from_list(domain, [[0, 1, 2], + [1, 2, "?"], + ["m", 3, "a"], + ["?", "?", "c"]]) + self.assertIs(table.domain, domain) + np.testing.assert_almost_equal( + table.X, np.array([[0, 1], [1, 2], [0, 3], [np.nan, np.nan]])) + np.testing.assert_almost_equal(table.Y, np.array([2, np.nan, 0, 2])) + + def test_creates_a_table_from_domain_and_list_and_weights(self): + domain = data.Domain([data.DiscreteVariable(name="a", values="mf"), + data.ContinuousVariable(name="b")], + data.DiscreteVariable(name="y", values="abc")) + table = data.Table.from_list(domain, [[0, 1, 2], + [1, 2, "?"], + ["m", 3, "a"], + ["?", "?", "c"]], [1, 2, 3, 4]) + self.assertIs(table.domain, domain) + np.testing.assert_almost_equal( + table.X, np.array([[0, 1], [1, 2], [0, 3], [np.nan, np.nan]])) + np.testing.assert_almost_equal(table.Y, np.array([2, np.nan, 0, 2])) + np.testing.assert_almost_equal(table.W, np.array([1, 2, 3, 4])) + + def test_creates_a_table_from_domain_and_list_and_metas(self): + metas = [data.DiscreteVariable("Meta 1", values="XYZ"), + data.ContinuousVariable("Meta 2"), + data.StringVariable("Meta 3")] + domain = data.Domain([data.DiscreteVariable(name="a", values="mf"), + data.ContinuousVariable(name="b")], + data.DiscreteVariable(name="y", values="abc"), + metas=metas) + table = data.Table.from_list(domain, [[0, 1, 2, "X", 2, "bb"], + [1, 2, "?", "Y", 1, "aa"], + ["m", 3, "a", "Z", 3, "bb"], + ["?", "?", "c", "X", 1, "aa"]]) + self.assertIs(table.domain, domain) + np.testing.assert_almost_equal( + table.X, np.array([[0, 1], [1, 2], [0, 3], [np.nan, np.nan]])) + np.testing.assert_almost_equal(table.Y, np.array([2, np.nan, 0, 2])) + np.testing.assert_array_equal(table.metas, + np.array([[0, 2., "bb"], + [1, 1., "aa"], + [2, 3., "bb"], + [0, 1., "aa"]], + dtype=object)) + + def test_creates_a_table_from_list_of_instances(self): + table = data.Table('iris') + new_table = data.Table.from_list(table.domain, [d for d in table]) + self.assertIs(table.domain, new_table.domain) + np.testing.assert_almost_equal(table.X, new_table.X) + np.testing.assert_almost_equal(table.Y, new_table.Y) + np.testing.assert_almost_equal(table.W, new_table.W) + self.assertEqual(table.domain, new_table.domain) + np.testing.assert_array_equal(table.metas, new_table.metas) + + def test_creates_a_table_from_list_of_instances_with_metas(self): + table = data.Table('zoo') + new_table = data.Table.from_list(table.domain, [d for d in table]) + self.assertIs(table.domain, new_table.domain) + np.testing.assert_almost_equal(table.X, new_table.X) + np.testing.assert_almost_equal(table.Y, new_table.Y) + np.testing.assert_almost_equal(table.W, new_table.W) + self.assertEqual(table.domain, new_table.domain) + np.testing.assert_array_equal(table.metas, new_table.metas) + + def test_creates_a_table_with_domain_and_given_X(self): + domain = self.mock_domain() + + table = data.Table(domain, self.data) + self.assertIsInstance(table.domain, data.Domain) + self.assertEqual(table.domain, domain) + np.testing.assert_almost_equal(table.X, self.data) + + def test_creates_a_table_with_given_X_and_Y(self): + table = data.Table.from_numpy(None, self.data, self.class_data) + + self.assertIsInstance(table.domain, data.Domain) + np.testing.assert_almost_equal(table.X, self.data) + np.testing.assert_almost_equal(table.Y, self.class_data) + + def test_creates_a_table_with_given_X_Y_and_metas(self): + table = data.Table.from_numpy( + None, self.data, self.class_data, self.meta_data) + + self.assertIsInstance(table.domain, data.Domain) + np.testing.assert_almost_equal(table.X, self.data) + np.testing.assert_almost_equal(table.Y, self.class_data) + np.testing.assert_almost_equal(table.metas, self.meta_data) + + def test_creates_a_discrete_class_if_Y_has_few_distinct_values(self): + Y = np.array([float(np.random.randint(0, 2)) for i in self.data]) + table = data.Table.from_numpy(None, self.data, Y, self.meta_data) + + np.testing.assert_almost_equal(table.Y, Y) + self.assertIsInstance(table.domain.class_vars[0], + data.DiscreteVariable) + self.assertEqual(table.domain.class_vars[0].values, ["v1", "v2"]) + + def test_creates_a_table_with_given_domain(self): + domain = self.mock_domain() + table = data.Table.from_numpy(domain, self.data) + + self.assertEqual(table.domain, domain) + + def test_sets_Y_if_given(self): + domain = self.mock_domain(with_classes=True) + table = data.Table.from_numpy(domain, self.data, self.class_data) + + np.testing.assert_almost_equal(table.Y, self.class_data) + + def test_sets_metas_if_given(self): + domain = self.mock_domain(with_metas=True) + table = data.Table.from_numpy(domain, self.data, metas=self.meta_data) + + np.testing.assert_almost_equal(table.metas, self.meta_data) + + def test_sets_weights_if_given(self): + domain = self.mock_domain() + table = data.Table.from_numpy(domain, self.data, W=self.weight_data) + + np.testing.assert_equal(table.W.shape, (len(self.data), )) + np.testing.assert_almost_equal(table.W.flatten(), + self.weight_data.flatten()) + + def test_splits_X_and_Y_if_given_in_same_array(self): + joined_data = np.column_stack((self.data, self.class_data)) + domain = self.mock_domain(with_classes=True) + table = data.Table.from_numpy(domain, joined_data) + + np.testing.assert_almost_equal(table.X, self.data) + np.testing.assert_almost_equal(table.Y, self.class_data) + + def test_initializes_Y_metas_and_W_if_not_given(self): + domain = self.mock_domain() + table = data.Table.from_numpy(domain, self.data) + + self.assertEqual(table.Y.shape, (self.nrows, len(domain.class_vars))) + self.assertEqual(table.metas.shape, (self.nrows, len(domain.metas))) + self.assertEqual(table.W.shape, (self.nrows, 0)) + + def test_raises_error_if_columns_in_domain_and_data_do_not_match(self): + domain = self.mock_domain(with_classes=True, with_metas=True) + ones = np.zeros((self.nrows, 1)) + + with self.assertRaises(ValueError): + data_ = np.hstack((self.data, ones)) + data.Table.from_numpy(domain, data_, self.class_data, + self.meta_data) + + with self.assertRaises(ValueError): + classes_ = np.hstack((self.class_data, ones)) + data.Table.from_numpy(domain, self.data, classes_, + self.meta_data) + + with self.assertRaises(ValueError): + metas_ = np.hstack((self.meta_data, ones)) + data.Table.from_numpy(domain, self.data, self.class_data, + metas_) + + def test_raises_error_if_lengths_of_data_do_not_match(self): + domain = self.mock_domain(with_classes=True, with_metas=True) + + with self.assertRaises(ValueError): + data_ = np.vstack((self.data, np.zeros((1, len(self.attributes))))) + data.Table(domain, data_, self.class_data, self.meta_data) + + with self.assertRaises(ValueError): + class_data_ = np.vstack((self.class_data, + np.zeros((1, len(self.class_vars))))) + data.Table(domain, self.data, class_data_, self.meta_data) + + with self.assertRaises(ValueError): + meta_data_ = np.vstack((self.meta_data, + np.zeros((1, len(self.metas))))) + data.Table(domain, self.data, self.class_data, meta_data_) + + @patch("Orange.data.table.Table.from_numpy") + def test_calling_new_with_domain_and_numpy_arrays_calls_new_from_numpy( + self, new_from_numpy): + domain = self.mock_domain() + data.Table(domain, self.data) + new_from_numpy.assert_called_with(domain, self.data) + + domain = self.mock_domain(with_classes=True) + data.Table(domain, self.data, self.class_data) + new_from_numpy.assert_called_with(domain, self.data, self.class_data) + + domain = self.mock_domain(with_classes=True, with_metas=True) + data.Table(domain, self.data, self.class_data, self.meta_data) + new_from_numpy.assert_called_with( + domain, self.data, self.class_data, self.meta_data) + + data.Table(domain, self.data, self.class_data, + self.meta_data, self.weight_data) + new_from_numpy.assert_called_with(domain, self.data, self.class_data, + self.meta_data, self.weight_data) + + def test_from_numpy_reconstructable(self): + def assert_equal(t1, t2): + np.testing.assert_array_equal(t1.X, t2.X) + np.testing.assert_array_equal(t1.Y, t2.Y) + np.testing.assert_array_equal(t1.metas, t2.metas) + np.testing.assert_array_equal(t1.W, t2.W) + + nullcol = np.empty((self.nrows, 0)) + domain = self.create_domain(self.attributes) + table = data.Table(domain, self.data) + + table_1 = data.Table.from_numpy( + domain, table.X, table.Y, table.metas, table.W) + assert_equal(table, table_1) + + domain = self.create_domain(classes=self.class_vars) + table = data.Table(domain, nullcol, self.class_data) + + table_1 = data.Table.from_numpy( + domain, table.X, table.Y, table.metas, table.W) + assert_equal(table, table_1) + + domain = self.create_domain(metas=self.metas) + table = data.Table(domain, nullcol, nullcol, self.meta_data) + + table_1 = data.Table.from_numpy( + domain, table.X, table.Y, table.metas, table.W) + assert_equal(table, table_1) + + +class CreateTableWithDomainAndTable(TableTests): + interesting_slices = [ + slice(0, 0), # [0:0] - empty slice + slice(1), # [:1] - only first element + slice(1, None), # [1:] - all but first + slice(-1, None), # [-1:] - only last element + slice(-1), # [:-1] - all but last + slice(None), # [:] - all elements + slice(None, None, 2), # [::2] - even elements + slice(None, None, -1), # [::-1]- all elements reversed + ] + + row_indices = [1, 5, 6, 7] + + def setUp(self): + self.domain = self.create_domain( + self.attributes, self.class_vars, self.metas) + self.table = data.Table( + self.domain, self.data, self.class_data, self.meta_data) + + def test_creates_table_with_given_domain(self): + new_table = data.Table.from_table(self.table.domain, self.table) + + self.assertIsInstance(new_table, data.Table) + self.assertIsNot(self.table, new_table) + self.assertEqual(new_table.domain, self.domain) + + def test_transform(self): + class MyTableClass(data.Table): + pass + + table = MyTableClass.from_table(self.table.domain, self.table) + domain = table.domain + attr = ContinuousVariable("x") + new_domain = data.Domain(list(domain.attributes) + [attr], None) + new_table = table.transform(new_domain) + + self.assertIsInstance(new_table, MyTableClass) + self.assertIsNot(table, new_table) + self.assertIs(new_table.domain, new_domain) + + def test_transform_same_domain(self): + iris = data.Table("iris") + new_domain = copy.copy(iris.domain) + new_data = iris.transform(new_domain) + self.assertIs(new_data.domain, new_domain) + + def test_can_copy_table(self): + new_table = data.Table.from_table(self.domain, self.table) + self.assert_table_with_filter_matches(new_table, self.table) + + def test_can_filter_rows_with_list(self): + for indices in ([0], [1, 5, 6, 7]): + new_table = data.Table.from_table( + self.domain, self.table, row_indices=indices) + self.assert_table_with_filter_matches( + new_table, self.table, rows=indices) + + def test_can_filter_row_with_slice(self): + for slice_ in self.interesting_slices: + new_table = data.Table.from_table( + self.domain, self.table, row_indices=slice_) + self.assert_table_with_filter_matches( + new_table, self.table, rows=slice_) + + def test_can_use_attributes_as_new_columns(self): + a, _, _ = column_sizes(self.table) + order = [random.randrange(a) for _ in self.domain.attributes] + new_attributes = [self.domain.attributes[i] for i in order] + new_domain = self.create_domain( + new_attributes, new_attributes, new_attributes) + new_table = data.Table.from_table(new_domain, self.table) + + self.assert_table_with_filter_matches( + new_table, self.table, xcols=order, ycols=order, mcols=order) + + def test_can_use_class_vars_as_new_columns(self): + a, c, _ = column_sizes(self.table) + order = [random.randrange(a, a + c) for _ in self.domain.class_vars] + new_classes = [self.domain.class_vars[i - a] for i in order] + new_domain = self.create_domain(new_classes, new_classes, new_classes) + new_table = data.Table.from_table(new_domain, self.table) + + self.assert_table_with_filter_matches( + new_table, self.table, xcols=order, ycols=order, mcols=order) + + def test_can_use_metas_as_new_columns(self): + _, _, m = column_sizes(self.table) + order = [random.randrange(-m + 1, 0) for _ in self.domain.metas] + new_metas = [self.domain.metas[::-1][i] for i in order] + new_domain = self.create_domain(new_metas, new_metas, new_metas) + new_table = data.Table.from_table(new_domain, self.table) + + self.assert_table_with_filter_matches( + new_table, self.table, xcols=order, ycols=order, mcols=order) + + def test_can_use_combination_of_all_as_new_columns(self): + a, c, m = column_sizes(self.table) + order = ([random.randrange(a) for _ in self.domain.attributes] + + [random.randrange(a, a + c) for _ in self.domain.class_vars] + + [random.randrange(-m + 1, 0) for _ in self.domain.metas]) + random.shuffle(order) + vars = list(self.domain.variables) + list(self.domain.metas[::-1]) + vars = [vars[i] for i in order] + + new_domain = self.create_domain(vars, vars, vars) + new_table = data.Table.from_table(new_domain, self.table) + self.assert_table_with_filter_matches( + new_table, self.table, xcols=order, ycols=order, mcols=order) + + def test_creates_table_with_given_domain_and_row_filter(self): + a, c, m = column_sizes(self.table) + order = ([random.randrange(a) for _ in self.domain.attributes] + + [random.randrange(a, a + c) for _ in self.domain.class_vars] + + [random.randrange(-m + 1, 0) for _ in self.domain.metas]) + random.shuffle(order) + vars = list(self.domain.variables) + list(self.domain.metas[::-1]) + vars = [vars[i] for i in order] + + new_domain = self.create_domain(vars, vars, vars) + new_table = data.Table.from_table(new_domain, self.table, [0]) + self.assert_table_with_filter_matches( + new_table, self.table[:1], xcols=order, ycols=order, mcols=order) + + new_table = data.Table.from_table(new_domain, self.table, [2, 1, 0]) + self.assert_table_with_filter_matches( + new_table, self.table[2::-1], xcols=order, ycols=order, mcols=order) + + new_table = data.Table.from_table(new_domain, self.table, []) + self.assert_table_with_filter_matches( + new_table, self.table[:0], xcols=order, ycols=order, mcols=order) + + def test_from_table_sparse_move_some_to_empty_metas(self): + iris = data.Table("iris").to_sparse() + new_domain = data.domain.Domain( + iris.domain.attributes[:2], iris.domain.class_vars, + iris.domain.attributes[2:], source=iris.domain) + new_iris = iris.transform(new_domain) + + self.assertTrue(sp.issparse(new_iris.X)) + self.assertTrue(sp.issparse(new_iris.metas)) + self.assertEqual(new_iris.X.shape, (len(iris), 2)) + self.assertEqual(new_iris.metas.shape, (len(iris), 2)) + + # move back + back_iris = new_iris.transform(iris.domain) + self.assertEqual(back_iris.domain, iris.domain) + self.assertTrue(sp.issparse(back_iris.X)) + self.assertFalse(sp.issparse(back_iris.metas)) + self.assertEqual(back_iris.X.shape, iris.X.shape) + self.assertEqual(back_iris.metas.shape, iris.metas.shape) + + def test_from_table_sparse_move_all_to_empty_metas(self): + iris = data.Table("iris").to_sparse() + new_domain = data.domain.Domain( + [], iris.domain.class_vars, iris.domain.attributes, + source=iris.domain) + new_iris = iris.transform(new_domain) + + self.assertFalse(sp.issparse(new_iris.X)) + self.assertTrue(sp.issparse(new_iris.metas)) + self.assertEqual(new_iris.X.shape, (len(iris), 0)) + self.assertEqual(new_iris.metas.shape, (len(iris), 4)) + + # move back + back_iris = new_iris.transform(iris.domain) + self.assertEqual(back_iris.domain, iris.domain) + self.assertTrue(sp.issparse(back_iris.X)) + self.assertFalse(sp.issparse(back_iris.metas)) + self.assertEqual(back_iris.X.shape, iris.X.shape) + self.assertEqual(back_iris.metas.shape, iris.metas.shape) + + def test_from_table_sparse_move_to_nonempty_metas(self): + brown = data.Table("brown-selected").to_sparse() + n_attr = len(brown.domain.attributes) + n_metas = len(brown.domain.metas) + new_domain = data.domain.Domain( + brown.domain.attributes[:-10], + brown.domain.class_vars, + brown.domain.attributes[-10:] + brown.domain.metas, + source=brown.domain) + new_brown = data.Table.from_table(new_domain, brown) + + self.assertTrue(sp.issparse(new_brown.X)) + self.assertFalse(sp.issparse(new_brown.metas)) + self.assertEqual(new_brown.X.shape, (len(new_brown), n_attr-10)) + self.assertEqual(new_brown.metas.shape, (len(new_brown), n_metas+10)) + + # move back + back_brown = data.Table.from_table(brown.domain, new_brown) + self.assertEqual(brown.domain, back_brown.domain) + self.assertTrue(sp.issparse(back_brown.X)) + self.assertFalse(sp.issparse(back_brown.metas)) + self.assertEqual(back_brown.X.shape, brown.X.shape) + self.assertEqual(back_brown.metas.shape, brown.metas.shape) + + def assert_table_with_filter_matches( + self, new_table, old_table, + rows=..., xcols=..., ycols=..., mcols=...): + a, c, m = column_sizes(old_table) + xcols = slice(a) if xcols is Ellipsis else xcols + ycols = slice(a, a + c) if ycols is Ellipsis else ycols + mcols = slice(None, -m - 1, -1) if mcols is Ellipsis else mcols + + # Indexing used by convert_domain uses positive indices for variables + # and classes (classes come after attributes) and negative indices for + # meta features. This is equivalent to ordinary indexing in a magic + # table below. + magic = np.hstack((old_table.X, old_table.Y[:, None], + old_table.metas[:, ::-1])) + np.testing.assert_almost_equal(new_table.X, magic[rows, xcols]) + Y = magic[rows, ycols] + if Y.shape[1] == 1: + Y = Y.flatten() + np.testing.assert_almost_equal(new_table.Y, Y) + np.testing.assert_almost_equal(new_table.metas, magic[rows, mcols]) + np.testing.assert_almost_equal(new_table.W, old_table.W[rows]) + + +def isspecial(s): + return isinstance(s, slice) or s is Ellipsis + + +def split_columns(indices, t): + a, c, m = column_sizes(t) + if indices is ...: + return slice(a), slice(c), slice(m) + elif isinstance(indices, slice): + return indices, slice(0, 0), slice(0, 0) + elif not isinstance(indices, list) and not isinstance(indices, tuple): + indices = [indices] + return ( + [t.domain.index(x) + for x in indices if 0 <= t.domain.index(x) < a] or slice(0, 0), + [t.domain.index(x) - a + for x in indices if t.domain.index(x) >= a] or slice(0, 0), + [-t.domain.index(x) - 1 + for x in indices if t.domain.index(x) < 0] or slice(0, 0)) + + +def getname(variable): + return variable.name + + +class TableIndexingTests(TableTests): + def setUp(self): + super().setUp() + d = self.domain = \ + self.create_domain(self.attributes, self.class_vars, self.metas) + t = self.table = \ + data.Table(self.domain, self.data, self.class_data, self.meta_data) + self.magic_table = \ + np.column_stack((self.table.X, self.table.Y, + self.table.metas[:, ::-1])) + + self.rows = [0, -1] + self.multiple_rows = [slice(0, 0), ..., slice(1, -1, -1)] + a, c, m = column_sizes(t) + columns = [0, a - 1, a, a + c - 1, -1, -m] + self.columns = chain(columns, + map(lambda x: d[x], columns), + map(lambda x: d[x].name, columns)) + self.multiple_columns = chain( + self.multiple_rows, + [d.attributes, d.class_vars, d.metas, [0, a, -1]], + [self.attributes, self.class_vars, self.metas], + [self.attributes + self.class_vars + self.metas]) + + # TODO: indexing with [[0,1], [0,1]] produces weird results + # TODO: what should be the results of table[1, :] + + def test_can_select_a_single_value(self): + for r in self.rows: + for c in self.columns: + value = self.table[r, c] + self.assertAlmostEqual( + value, self.magic_table[r, self.domain.index(c)]) + + value = self.table[r][c] + self.assertAlmostEqual( + value, self.magic_table[r, self.domain.index(c)]) + + def test_can_select_a_single_row(self): + for r in self.rows: + row = self.table[r] + new_row = np.hstack( + (self.data[r, :], + self.class_data[r, None])) + np.testing.assert_almost_equal( + np.array(list(row)), new_row) + + + def test_can_select_a_subset_of_rows_and_columns(self): + for r in self.rows: + for c in self.multiple_columns: + table = self.table[r, c] + + attr, cls, metas = split_columns(c, self.table) + X = self.table.X[[r], attr] + if X.ndim == 1: + X = X.reshape(-1, len(table.domain.attributes)) + np.testing.assert_almost_equal(table.X, X) + Y = self.table.Y[:, None][[r], cls] + if len(Y.shape) == 1 or Y.shape[1] == 1: + Y = Y.flatten() + np.testing.assert_almost_equal(table.Y, Y) + metas_ = self.table.metas[[r], metas] + if metas_.ndim == 1: + metas_ = metas_.reshape(-1, len(table.domain.metas)) + np.testing.assert_almost_equal(table.metas, metas_) + + for r in self.multiple_rows: + for c in chain(self.columns, self.multiple_rows): + table = self.table[r, c] + + attr, cls, metas = split_columns(c, self.table) + np.testing.assert_almost_equal(table.X, self.table.X[r, attr]) + Y = self.table.Y[:, None][r, cls] + if len(Y.shape) > 1 and Y.shape[1] == 1: + Y = Y.flatten() + np.testing.assert_almost_equal(table.Y, Y) + np.testing.assert_almost_equal(table.metas, + self.table.metas[r, metas]) + + + def test_optimize_indices(self): + # ordinary conversion + self.assertEqual(_optimize_indices([1, 2, 3], 4), slice(1, 4, 1)) + self.assertEqual(_optimize_indices([], 1), []) + self.assertEqual(_optimize_indices([0, 2], 3), slice(0, 4, 2)) + + # not slices + np.testing.assert_equal(_optimize_indices([1, 2, 4], 5), [1, 2, 4]) + np.testing.assert_equal(_optimize_indices((1, 2, 4), 5), [1, 2, 4]) + + # leave boolean arrays + np.testing.assert_equal(_optimize_indices([True, False, True], 3), [True, False, True]) + + # do not convert if step is negative + np.testing.assert_equal(_optimize_indices([4, 2, 0], 5), [4, 2, 0]) + + # try range + np.testing.assert_equal(_optimize_indices([3, 4, 5], 5), [3, 4, 5]) # out of range + self.assertEqual(_optimize_indices((3, 4, 5), 6), slice(3, 6, 1)) + + # negative elements + np.testing.assert_equal(_optimize_indices([-1, 0, 1], 5), [-1, 0, 1]) + + # single element + self.assertEqual(_optimize_indices([1], 2), slice(1, 2, 1)) + np.testing.assert_equal(_optimize_indices([1], 1), [1]) + + +class TableElementAssignmentTest(TableTests): + def setUp(self): + super().setUp() + self.domain = \ + self.create_domain(self.attributes, self.class_vars, self.metas) + self.table = \ + data.Table(self.domain, self.data, self.class_data, self.meta_data) + + def test_can_assign_values(self): + self.table[0, 0] = 42. + self.assertAlmostEqual(self.table.X[0, 0], 42.) + + def test_can_assign_values_to_classes(self): + a, _, _ = column_sizes(self.table) + self.table[0, a] = 42. + self.assertAlmostEqual(self.table.Y[0], 42.) + + def test_can_assign_values_to_metas(self): + self.table[0, -1] = 42. + self.assertAlmostEqual(self.table.metas[0, 0], 42.) + + def test_can_assign_rows_to_rows(self): + self.table[0] = self.table[1] + np.testing.assert_almost_equal( + self.table.X[0], self.table.X[1]) + np.testing.assert_almost_equal( + self.table.Y[0], self.table.Y[1]) + np.testing.assert_almost_equal( + self.table.metas[0], self.table.metas[1]) + + def test_can_assign_lists(self): + a, _, _ = column_sizes(self.table) + new_example = [float(i) + for i in range(len(self.attributes + self.class_vars))] + self.table[0] = new_example + np.testing.assert_almost_equal( + self.table.X[0], np.array(new_example[:a])) + np.testing.assert_almost_equal( + self.table.Y[0], np.array(new_example[a:])) + + def test_can_assign_np_array(self): + a, _, _ = column_sizes(self.table) + new_example = \ + np.array([float(i) + for i in range(len(self.attributes + self.class_vars))]) + self.table[0] = new_example + np.testing.assert_almost_equal(self.table.X[0], new_example[:a]) + np.testing.assert_almost_equal(self.table.Y[0], new_example[a:]) + + +class InterfaceTest(unittest.TestCase): + """Basic tests each implementation of Table should pass.""" + + features = ( + data.ContinuousVariable(name="Continuous Feature 1"), + data.ContinuousVariable(name="Continuous Feature 2"), + data.DiscreteVariable(name="Discrete Feature 1", values=["0", "1"]), + data.DiscreteVariable(name="Discrete Feature 2", + values=["value1", "value2"]), + ) + + class_vars = ( + data.ContinuousVariable(name="Continuous Class"), + data.DiscreteVariable(name="Discrete Class", values=["m", "f"]) + ) + + feature_data = ( + (1, 0, 0, 0), + (0, 1, 0, 0), + (0, 0, 1, 0), + (0, 0, 0, 1), + ) + + class_data = ( + (1, 0), + (0, 1), + (1, 0), + (0, 1) + ) + + data = tuple(a + c for a, c in zip(feature_data, class_data)) + + nrows = 4 + + def setUp(self): + self.domain = data.Domain(attributes=self.features, + class_vars=self.class_vars) + self.table = data.Table.from_numpy( + self.domain, + np.array(self.feature_data), + np.array(self.class_data), + ) + + def test_len(self): + self.assertEqual(len(self.table), self.nrows) + + def test_row_len(self): + for i in range(self.nrows): + self.assertEqual(len(self.table[i]), len(self.data[i])) + + def test_iteration(self): + for row, expected_data in zip(self.table, self.data): + self.assertEqual(tuple(row), expected_data) + + def test_row_indexing(self): + for i in range(self.nrows): + self.assertEqual(tuple(self.table[i]), self.data[i]) + + def test_row_slicing(self): + t = self.table[1:] + self.assertEqual(len(t), self.nrows - 1) + + def test_value_indexing(self): + for i in range(self.nrows): + for j in range(len(self.table[i])): + self.assertEqual(self.table[i, j], self.data[i][j]) + + def test_row_assignment(self): + new_value = 2. + for i in range(self.nrows): + new_row = [new_value] * len(self.data[i]) + self.table[i] = np.array(new_row) + self.assertEqual(list(self.table[i]), new_row) + + def test_value_assignment(self): + new_value = 0. + for i in range(self.nrows): + for j in range(len(self.table[i])): + self.table[i, j] = new_value + self.assertEqual(self.table[i, j], new_value) + + def test_subclasses(self): + from pathlib import Path + + class _ExtendedTable(data.Table): + pass + + data_file = _ExtendedTable('iris') + data_url = _ExtendedTable.from_url( + Path(os.path.dirname(__file__), 'datasets/test1.tab').as_uri()) + + self.assertIsInstance(data_file, _ExtendedTable) + self.assertIsInstance(data_url, _ExtendedTable) + + +class TestTableStats(TableTests): + def test_get_nan_frequency(self): + domain = self.create_domain(self.attributes, self.class_vars) + table = data.Table(domain, self.data, self.class_data) + self.assertEqual(table.get_nan_frequency_attribute(), 0) + self.assertEqual(table.get_nan_frequency_class(), 0) + + table.X[1, 2] = table.X[4, 5] = np.nan + self.assertEqual(table.get_nan_frequency_attribute(), 2 / table.X.size) + self.assertEqual(table.get_nan_frequency_class(), 0) + + table.Y[3:6] = np.nan + self.assertEqual(table.get_nan_frequency_attribute(), 2 / table.X.size) + self.assertEqual(table.get_nan_frequency_class(), 3 / table.Y.size) + + table.X[1, 2] = table.X[4, 5] = 0 + self.assertEqual(table.get_nan_frequency_attribute(), 0) + self.assertEqual(table.get_nan_frequency_class(), 3 / table.Y.size) + + def test_get_nan_frequency_empty_table(self): + domain = self.create_domain(self.attributes, self.class_vars) + table = data.Table.from_domain(domain) + self.assertEqual(table.get_nan_frequency_attribute(), 0) + self.assertEqual(table.get_nan_frequency_class(), 0) + + +class TestRowInstance(unittest.TestCase): + def test_assignment(self): + table = data.Table("zoo") + inst = table[2] + self.assertIsInstance(inst, data.RowInstance) + + inst[1] = 0 + self.assertEqual(table[2, 1], 0) + inst[1] = 1 + self.assertEqual(table[2, 1], 1) + + inst.set_class("mammal") + self.assertEqual(table[2, len(table.domain.attributes)], "mammal") + inst.set_class("fish") + self.assertEqual(table[2, len(table.domain.attributes)], "fish") + + inst[-1] = "Foo" + self.assertEqual(table[2, -1], "Foo") + + def test_iteration_with_assignment(self): + table = data.Table("iris") + for i, row in enumerate(table): + row[0] = i + np.testing.assert_array_equal(table.X[:, 0], np.arange(len(table))) + + def test_sparse_assignment(self): + X = np.eye(4) + Y = X[2] + table = data.Table.from_numpy(None, X, Y) + row = table[1] + self.assertFalse(sp.issparse(row.sparse_x)) + self.assertEqual(row[0], 0) + self.assertEqual(row[1], 1) + + table.X = sp.csr_matrix(table.X) + table._Y = sp.csr_matrix(table._Y) + sparse_row = table[1] + self.assertTrue(sp.issparse(sparse_row.sparse_x)) + self.assertEqual(sparse_row[0], 0) + self.assertEqual(sparse_row[1], 1) + sparse_row[1] = 0 + self.assertEqual(sparse_row[1], 0) + self.assertEqual(table.X[1, 1], 0) + self.assertEqual(table[2][4], 1) + table[2][4] = 0 + self.assertEqual(table[2][4], 0) + + +class TestTableTranspose(unittest.TestCase): + def test_transpose_no_class(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + data = Table(Domain(attrs), np.arange(8).reshape((4, 2))) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose is original + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_discrete_class(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + domain = Domain(attrs, [DiscreteVariable("cls", values=["a", "b"])]) + data = Table(domain, np.arange(8).reshape((4, 2)), + np.array([1, 1, 0, 0])) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"cls": "b"} + att[1].attributes = {"cls": "b"} + att[2].attributes = {"cls": "a"} + att[3].attributes = {"cls": "a"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose is original + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_continuous_class(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + domain = Domain(attrs, [ContinuousVariable("cls")]) + data = Table(domain, np.arange(8).reshape((4, 2)), np.arange(4, 0, -1)) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"cls": "4"} + att[1].attributes = {"cls": "3"} + att[2].attributes = {"cls": "2"} + att[3].attributes = {"cls": "1"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_missing_class(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + domain = Domain(attrs, [ContinuousVariable("cls")]) + data = Table(domain, np.arange(8).reshape((4, 2)), + np.array([np.nan, 3, 2, 1])) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[1].attributes = {"cls": "3"} + att[2].attributes = {"cls": "2"} + att[3].attributes = {"cls": "1"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_multiple_class(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + class_vars = [ContinuousVariable("cls1"), ContinuousVariable("cls2")] + domain = Domain(attrs, class_vars) + data = Table(domain, np.arange(8).reshape((4, 2)), + np.arange(8).reshape((4, 2))) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"cls1": "0", "cls2": "1"} + att[1].attributes = {"cls1": "2", "cls2": "3"} + att[2].attributes = {"cls1": "4", "cls2": "5"} + att[3].attributes = {"cls1": "6", "cls2": "7"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [StringVariable("m1")] + domain = Domain(attrs, metas=metas) + X = np.arange(8).reshape((4, 2)) + M = np.array(["aa", "bb", "cc", "dd"])[:, None] + data = Table(domain, X, metas=M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"m1": "aa"} + att[1].attributes = {"m1": "bb"} + att[2].attributes = {"m1": "cc"} + att[3].attributes = {"m1": "dd"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_discrete_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [DiscreteVariable("m1", values=["aa", "bb"])] + domain = Domain(attrs, metas=metas) + X = np.arange(8).reshape((4, 2)) + M = np.array([0, 1, 0, 1])[:, None] + data = Table(domain, X, metas=M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"m1": "aa"} + att[1].attributes = {"m1": "bb"} + att[2].attributes = {"m1": "aa"} + att[3].attributes = {"m1": "bb"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose is original + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_continuous_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [ContinuousVariable("m1")] + domain = Domain(attrs, metas=metas) + X = np.arange(8).reshape((4, 2)) + M = np.array([0.0, 1.0, 0.0, 1.0])[:, None] + data = Table(domain, X, metas=M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"m1": "0"} + att[1].attributes = {"m1": "1"} + att[2].attributes = {"m1": "0"} + att[3].attributes = {"m1": "1"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose is original + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_missing_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [StringVariable("m1")] + domain = Domain(attrs, metas=metas) + X = np.arange(8).reshape((4, 2)) + M = np.array(["aa", "bb", "", "dd"])[:, None] + data = Table(domain, X, metas=M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"m1": "aa"} + att[1].attributes = {"m1": "bb"} + att[3].attributes = {"m1": "dd"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_multiple_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [StringVariable("m1"), StringVariable("m2")] + domain = Domain(attrs, metas=metas) + X = np.arange(8).reshape((4, 2)) + M = np.array([["aa", "aaa"], ["bb", "bbb"], + ["cc", "ccc"], ["dd", "ddd"]]) + data = Table(domain, X, metas=M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"m1": "aa", "m2": "aaa"} + att[1].attributes = {"m1": "bb", "m2": "bbb"} + att[2].attributes = {"m1": "cc", "m2": "ccc"} + att[3].attributes = {"m1": "dd", "m2": "ddd"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_class_and_metas(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + metas = [StringVariable("m1"), StringVariable("m2")] + domain = Domain(attrs, [ContinuousVariable("cls")], metas) + M = np.array([["aa", "aaa"], ["bb", "bbb"], + ["cc", "ccc"], ["dd", "ddd"]]) + data = Table(domain, np.arange(8).reshape((4, 2)), np.arange(1, 5), M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"cls": "1", "m1": "aa", "m2": "aaa"} + att[1].attributes = {"cls": "2", "m1": "bb", "m2": "bbb"} + att[2].attributes = {"cls": "3", "m1": "cc", "m2": "ccc"} + att[3].attributes = {"cls": "4", "m1": "dd", "m2": "ddd"} + domain = Domain(att, metas=[StringVariable("Feature name")]) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array(["c1", "c2"])[:, None]) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, {}) + + def test_transpose_attributes_of_attributes_discrete(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + attrs[0].attributes = {"attr1": "a", "attr2": "aa"} + attrs[1].attributes = {"attr1": "b", "attr2": "bb"} + domain = Domain(attrs) + data = Table(domain, np.arange(8).reshape((4, 2))) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + metas = [StringVariable("Feature name"), + DiscreteVariable("attr1", values=("a", "b")), + DiscreteVariable("attr2", values=("aa", "bb"))] + domain = Domain(att, metas=metas) + M = np.array([["c1", 0.0, 0.0], ["c2", 1.0, 1.0]], dtype=object) + result = Table(domain, np.arange(8).reshape((4, 2)).T, metas=M) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, + {"attr1": "a", "attr2": "aa"}) + + def test_transpose_attributes_of_attributes_continuous(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + attrs[0].attributes = {"attr1": "1.1", "attr2": "1.3"} + attrs[1].attributes = {"attr1": "2.2", "attr2": "2.3"} + domain = Domain(attrs) + data = Table(domain, np.arange(8).reshape((4, 2))) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + metas = [StringVariable("Feature name"), ContinuousVariable("attr1"), + ContinuousVariable("attr2")] + domain = Domain(att, metas=metas) + result = Table(domain, np.arange(8).reshape((4, 2)).T, + metas=np.array([["c1", 1.1, 1.3], + ["c2", 2.2, 2.3]], dtype=object)) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, + {"attr1": "1.1", "attr2": "1.3"}) + + def test_transpose_attributes_of_attributes_missings(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + attrs[0].attributes = {"attr1": "a", "attr2": "aa"} + attrs[1].attributes = {"attr1": "b"} + domain = Domain(attrs) + data = Table(domain, np.arange(8).reshape((4, 2))) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + metas = [StringVariable("Feature name"), + DiscreteVariable("attr1", values=("a", "b")), + DiscreteVariable("attr2", values=("aa",))] + domain = Domain(att, metas=metas) + M = np.array([["c1", 0.0, 0.0], ["c2", 1.0, np.nan]], dtype=object) + result = Table(domain, np.arange(8).reshape((4, 2)).T, metas=M) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, + {"attr1": "a", "attr2": "aa"}) + + def test_transpose_class_metas_attributes(self): + attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")] + attrs[0].attributes = {"attr1": "a1", "attr2": "aa1"} + attrs[1].attributes = {"attr1": "b1", "attr2": "bb1"} + metas = [StringVariable("m1"), StringVariable("m2")] + domain = Domain(attrs, [ContinuousVariable("cls")], metas) + M = np.array([["aa", "aaa"], ["bb", "bbb"], + ["cc", "ccc"], ["dd", "ddd"]]) + data = Table(domain, np.arange(8).reshape((4, 2)), np.arange(1, 5), M) + + att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"), + ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")] + att[0].attributes = {"cls": "1", "m1": "aa", "m2": "aaa"} + att[1].attributes = {"cls": "2", "m1": "bb", "m2": "bbb"} + att[2].attributes = {"cls": "3", "m1": "cc", "m2": "ccc"} + att[3].attributes = {"cls": "4", "m1": "dd", "m2": "ddd"} + metas = [StringVariable("Feature name"), + DiscreteVariable("attr1", values=("a1", "b1")), + DiscreteVariable("attr2", values=("aa1", "bb1"))] + domain = Domain(att, metas=metas) + M = np.array([["c1", 0.0, 0.0], ["c2", 1.0, 1.0]], dtype=object) + result = Table(domain, np.arange(8).reshape((4, 2)).T, metas=M) + + # transpose and compare + self._compare_tables(result, Table.transpose(data)) + + # transpose of transpose + t = Table.transpose(Table.transpose(data), "Feature name") + self._compare_tables(data, t) + + # original should not change + self.assertDictEqual(data.domain.attributes[0].attributes, + {"attr1": "a1", "attr2": "aa1"}) + + def test_transpose_duplicate_feature_names(self): + table = Table("iris") + domain = table.domain + attrs, metas = domain.attributes[:3], domain.attributes[3:] + table = table.transform(Domain(attrs, domain.class_vars, metas)) + transposed = Table.transpose(table, domain.attributes[3].name) + names = [f.name for f in transposed.domain.attributes] + self.assertEqual(len(names), len(set(names))) + + def test_transpose(self): + zoo = Table("zoo") + t1 = Table.transpose(zoo) + t2 = Table.transpose(t1, "Feature name") + t3 = Table.transpose(t2) + self._compare_tables(zoo, t2) + self._compare_tables(t1, t3) + + def _compare_tables(self, table1, table2): + self.assertEqual(table1.n_rows, table2.n_rows) + np.testing.assert_array_equal(table1.X, table2.X) + np.testing.assert_array_equal(table1.Y, table2.Y) + np.testing.assert_array_equal(table1.metas.astype(str), + table2.metas.astype(str)) + np.testing.assert_array_equal(table1.W, table2.W) + + self.assertEqual([(type(x), x.name, x.attributes) + for x in table1.domain.attributes], + [(type(x), x.name, x.attributes) + for x in table2.domain.attributes]) + self.assertEqual([(type(x), x.name, x.attributes) + for x in table1.domain.class_vars], + [(type(x), x.name, x.attributes) + for x in table2.domain.class_vars]) + self.assertEqual([(type(x), x.name, x.attributes) + for x in table1.domain.metas], + [(type(x), x.name, x.attributes) + for x in table2.domain.metas]) + + +class SparseCV: + def __call__(self, data): + return sp.csr_matrix((len(data), 1)) + + +class TestTableSparseDense(unittest.TestCase): + def setUp(self): + self.iris = Table('iris') + + def test_sparse_dense_transformation(self): + iris = Table('iris') + iris_sparse = iris.to_sparse(sparse_attributes=True) + self.assertTrue(sp.issparse(iris_sparse.X)) + self.assertFalse(sp.issparse(iris_sparse.Y)) + self.assertFalse(sp.issparse(iris_sparse.metas)) + + iris_sparse = iris.to_sparse(sparse_attributes=True, sparse_class=True) + self.assertTrue(sp.issparse(iris_sparse.X)) + self.assertFalse(sp.issparse(iris_sparse.Y)) + self.assertFalse(sp.issparse(iris_sparse.metas)) + + dense_iris = iris_sparse.to_dense() + self.assertFalse(sp.issparse(dense_iris.X)) + self.assertFalse(sp.issparse(dense_iris.Y)) + self.assertFalse(sp.issparse(dense_iris.metas)) + + def test_from_table_add_one_sparse_column(self): + # add one sparse feature, should remain dense + domain = self.iris.domain.copy() + domain.attributes += ( + ContinuousVariable('S1', compute_value=SparseCV(), sparse=True), + ) + d = self.iris.transform(domain) + self.assertFalse(sp.issparse(d.X)) + + def test_from_table_add_lots_of_sparse_columns(self): + n_attrs = len(self.iris.domain.attributes) + + # add 2*n_attrs+1 sparse feature, should became sparse + domain = self.iris.domain.copy() + domain.attributes += tuple( + ContinuousVariable('S' + str(i), compute_value=SparseCV(), sparse=True) + for i in range(2*n_attrs + 1) + ) + d = self.iris.transform(domain) + self.assertTrue(sp.issparse(d.X)) + + def test_from_table_replace_attrs_with_sparse(self): + # replace attrs with a sparse feature, should became sparse + domain = self.iris.domain.copy() + domain.attributes = ( + ContinuousVariable('S1', compute_value=SparseCV(), sparse=True), + ) + d = self.iris.transform(domain) + self.assertTrue(sp.issparse(d.X)) + + def test_from_table_sparse_metas(self): + # replace metas with a sparse feature, should became sparse + domain = self.iris.domain.copy() + domain._metas = ( + ContinuousVariable('S1', compute_value=SparseCV(), sparse=True), + ) + d = self.iris.transform(domain) + self.assertTrue(sp.issparse(d.metas)) + + def test_from_table_sparse_metas_with_strings(self): + # replace metas with text and 100 sparse features, should be dense + domain = self.iris.domain.copy() + domain._metas = (StringVariable('text'),) + tuple( + ContinuousVariable('S' + str(i), compute_value=SparseCV(), sparse=True) + for i in range(100) + ) + d = self.iris.transform(domain) + self.assertFalse(sp.issparse(d.metas)) + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/test_third_party.py b/pyminer2/tests/test_third_party.py new file mode 100644 index 0000000000000000000000000000000000000000..b583fff486e000e4f7cf0aa8c455fab5955d6911 --- /dev/null +++ b/pyminer2/tests/test_third_party.py @@ -0,0 +1,10 @@ +from unittest import TestCase + +from pkg_resources import parse_version + + +class TestPkgResources(TestCase): + def test_parse_version(self): + self.assertGreater(parse_version('3.4.1'), parse_version('3.4.0')) + self.assertGreater(parse_version('3.4.1'), parse_version('3.4.dev')) + self.assertGreater(parse_version('3.4.0'), parse_version('3.4~1')) diff --git a/pyminer2/tests/test_transformation.py b/pyminer2/tests/test_transformation.py new file mode 100644 index 0000000000000000000000000000000000000000..b5c6b1216915a8205302332a8659e6f7be611698 --- /dev/null +++ b/pyminer2/tests/test_transformation.py @@ -0,0 +1,73 @@ +import unittest + +import numpy as np +import scipy.sparse as sp + +from Orange.data import Table, Domain, DiscreteVariable, ContinuousVariable, \ + StringVariable +from Orange.preprocess.transformation import Identity, Transformation, Lookup + + +class TestTransformation(unittest.TestCase): + class TransformationMock(Transformation): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.called_with = None + + def transform(self, col): + self.called_with = col + return np.arange(len(col)) + + @classmethod + def setUpClass(cls): + cls.data = Table("zoo") + + def test_call(self): + """Call passes the column to `transform` and returns its results""" + data = self.data + trans = self.TransformationMock(data.domain[2]) + np.testing.assert_almost_equal(trans(data), np.arange(len(data))) + np.testing.assert_array_equal(trans.called_with, data.X[:, 2]) + + np.testing.assert_almost_equal(trans(data[0]), np.array([0])) + np.testing.assert_array_equal(trans.called_with, data.X[0, 2]) + + trans = self.TransformationMock(data.domain.metas[0]) + np.testing.assert_almost_equal(trans(data), np.arange(len(data))) + np.testing.assert_array_equal(trans.called_with, data.metas.flatten()) + + np.testing.assert_almost_equal(trans(data[0]), np.array([0])) + np.testing.assert_array_equal(trans.called_with, data.metas[0, 0]) + + def test_transform_fails(self): + trans = Transformation(self.data.domain[2]) + self.assertRaises(NotImplementedError, trans, self.data) + + def test_identity(self): + domain = Domain([ContinuousVariable("X")], + [DiscreteVariable("C", values=["0", "1", "2"])], + [StringVariable("S")]) + X = np.random.normal(size=(4, 1)) + Y = np.random.randint(3, size=(4, 1)) + M = np.array(["A", "B", "C", "D"], dtype=object).reshape(-1, 1) + + D = Table.from_numpy(domain, X, Y, metas=M) + X1 = domain[0].copy(compute_value=Identity(domain[0])) + Y1 = domain[1].copy(compute_value=Identity(domain[1])) + S1 = domain.metas[0].copy(compute_value=Identity(domain.metas[0])) + domain_1 = Domain([X1], [Y1], [S1]) + D1 = Table.from_table(domain_1, D) + + np.testing.assert_equal(D1.X, D.X) + np.testing.assert_equal(D1.Y, D.Y) + np.testing.assert_equal(D1.metas, D.metas) + + +class LookupTest(unittest.TestCase): + def test_transform(self): + lookup = Lookup(None, np.array([1, 2, 0, 2])) + column = np.array([1, 2, 3, 0, np.nan, 0], dtype=np.float64) + for col in [column, sp.csr_matrix(column)]: + np.testing.assert_array_equal( + lookup.transform(col), + np.array([2, 0, 2, 1, np.nan, 1], dtype=np.float64)) diff --git a/pyminer2/tests/test_tree.py b/pyminer2/tests/test_tree.py new file mode 100644 index 0000000000000000000000000000000000000000..b3342cda68e94e2d78c532ea335c58d2640bb360 --- /dev/null +++ b/pyminer2/tests/test_tree.py @@ -0,0 +1,125 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from unittest.mock import Mock + +import numpy as np +import sklearn.tree as skl_tree +from sklearn.tree._tree import TREE_LEAF + +from Orange.data import Table +from Orange.classification import SklTreeLearner, TreeLearner +from Orange.regression import SklTreeRegressionLearner + + +class TestSklTreeLearner(unittest.TestCase): + def test_classification(self): + table = Table('iris') + learn = SklTreeLearner() + clf = learn(table) + Z = clf(table) + self.assertTrue(np.all(table.Y.flatten() == Z)) + + def test_regression(self): + table = Table('housing') + learn = SklTreeRegressionLearner() + model = learn(table) + pred = model(table) + self.assertTrue(np.all(table.Y.flatten() == pred)) + + +class TestTreeLearner(unittest.TestCase): + def test_uses_preprocessors(self): + iris = Table('iris') + mock_preprocessor = Mock(return_value=iris) + + tree = TreeLearner(preprocessors=[mock_preprocessor]) + tree(iris) + mock_preprocessor.assert_called_with(iris) + + +class TestDecisionTreeClassifier(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.iris = Table('iris') + + def test_full_tree(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier() + clf = clf.fit(table.X, table.Y) + Z = clf.predict(table.X) + self.assertTrue(np.all(table.Y.flatten() == Z)) + + def test_min_samples_split(self): + table = self.iris + lim = 5 + clf = skl_tree.DecisionTreeClassifier(min_samples_split=lim) + clf = clf.fit(table.X, table.Y) + t = clf.tree_ + for i in range(t.node_count): + if t.children_left[i] != TREE_LEAF: + self.assertGreaterEqual(t.n_node_samples[i], lim) + + def test_min_samples_leaf(self): + table = self.iris + lim = 5 + clf = skl_tree.DecisionTreeClassifier(min_samples_leaf=lim) + clf = clf.fit(table.X, table.Y) + t = clf.tree_ + for i in range(t.node_count): + if t.children_left[i] == TREE_LEAF: + self.assertGreaterEqual(t.n_node_samples[i], lim) + + def test_max_leaf_nodes(self): + table = self.iris + lim = 5 + clf = skl_tree.DecisionTreeClassifier(max_leaf_nodes=lim) + clf = clf.fit(table.X, table.Y) + t = clf.tree_ + self.assertLessEqual(t.node_count, lim * 2 - 1) + + def test_criterion(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier(criterion="entropy") + clf = clf.fit(table.X, table.Y) + + def test_splitter(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier(splitter="random") + clf = clf.fit(table.X, table.Y) + + def test_weights(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier(max_depth=2) + clf = clf.fit(table.X, table.Y) + clfw = skl_tree.DecisionTreeClassifier(max_depth=2) + clfw = clfw.fit(table.X, table.Y, sample_weight=np.arange(len(table))) + self.assertFalse(len(clf.tree_.feature) == len(clfw.tree_.feature) and + np.all(clf.tree_.feature == clfw.tree_.feature)) + + def test_impurity(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier() + clf = clf.fit(table.X, table.Y) + t = clf.tree_ + for i in range(t.node_count): + if t.children_left[i] == TREE_LEAF: + self.assertEqual(t.impurity[i], 0) + else: + l, r = t.children_left[i], t.children_right[i] + child_impurity = min(t.impurity[l], t.impurity[r]) + self.assertLessEqual(child_impurity, t.impurity[i]) + + def test_navigate_tree(self): + table = self.iris + clf = skl_tree.DecisionTreeClassifier(max_depth=1) + clf = clf.fit(table.X, table.Y.reshape(-1, 1)) + t = clf.tree_ + + x = table.X[0] + if x[t.feature[0]] <= t.threshold[0]: + v = t.value[t.children_left[0]][0] + else: + v = t.value[t.children_right[0]][0] + self.assertEqual(np.argmax(v), clf.predict(table.X[:1])) diff --git a/pyminer2/tests/test_txt_reader.py b/pyminer2/tests/test_txt_reader.py new file mode 100644 index 0000000000000000000000000000000000000000..4d115e1493a1eaa2df7bd3413a97c3c084a4dec5 --- /dev/null +++ b/pyminer2/tests/test_txt_reader.py @@ -0,0 +1,128 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +from tempfile import NamedTemporaryFile +import os +import io +import warnings + +from Orange.data import Table, ContinuousVariable, DiscreteVariable +from Orange.data.io import CSVReader +from Orange.tests import test_filename + +tab_file = """\ +Feature 1\tFeature 2\tFeature 3 +1.0 \t1.3 \t5 +2.0 \t42 \t7 +""" + +csv_file = """\ +Feature 1, Feature 2,Feature 3 +1.0, 1.3, 5 +2.0, 42, 7 +""" + +tab_file_nh = """\ +1.0 \t1.3 \t5 +2.0 \t42 \t7 +""" + +csv_file_nh = """\ +1.0, 1.3, 5 +2.0, 42, 7 +""" + +noncont_marked_cont = '''\ +a,b +d,c +, +e,1 +f,g +''' + + +csv_file_missing = """\ +A,B +1,A +2,B +3,A +?,B +5,? +""" + + +class TestTabReader(unittest.TestCase): + def read_easy(self, s, name): + file = NamedTemporaryFile("wt", delete=False) + filename = file.name + try: + file.write(s) + file.close() + table = CSVReader(filename).read() + + f1, f2, f3 = table.domain.variables + self.assertIsInstance(f1, DiscreteVariable) + self.assertEqual(f1.name, name + "1") + self.assertIsInstance(f2, ContinuousVariable) + self.assertEqual(f2.name, name + "2") + self.assertIsInstance(f3, ContinuousVariable) + self.assertEqual(f3.name, name + "3") + finally: + os.remove(filename) + + def test_read_tab(self): + self.read_easy(tab_file, "Feature ") + self.read_easy(tab_file_nh, "Feature ") + + def test_read_csv(self): + self.read_easy(csv_file, "Feature ") + self.read_easy(csv_file_nh, "Feature ") + + def test_read_csv_with_na(self): + c = io.StringIO(csv_file_missing) + table = CSVReader(c).read() + f1, f2 = table.domain.variables + self.assertIsInstance(f1, ContinuousVariable) + self.assertIsInstance(f2, DiscreteVariable) + + def test_read_nonutf8_encoding(self): + with self.assertRaises(ValueError) as cm: + data = Table(test_filename('datasets/binary-blob.tab')) + self.assertIn('NUL', cm.exception.args[0]) + + with self.assertRaises(ValueError): + with warnings.catch_warnings(): + warnings.filterwarnings('error') + data = Table(test_filename('datasets/invalid_characters.tab')) + + def test_noncontinous_marked_continuous(self): + file = NamedTemporaryFile("wt", delete=False) + file.write(noncont_marked_cont) + file.close() + with self.assertRaises(ValueError) as cm: + table = CSVReader(file.name).read() + self.assertIn('line 5, column 2', cm.exception.args[0]) + + def test_pr1734(self): + ContinuousVariable('foo') + file = NamedTemporaryFile("wt", delete=False) + filename = file.name + try: + file.write('''\ +foo +time + +123123123 +''') + file.close() + CSVReader(filename).read() + finally: + os.remove(filename) + + def test_csv_sniffer(self): + # GH-2785 + reader = CSVReader(test_filename('datasets/test_asn_data_working.csv')) + data = reader.read() + self.assertEqual(len(data), 8) + self.assertEqual(len(data.domain.variables) + len(data.domain.metas), 15) diff --git a/pyminer2/tests/test_util.py b/pyminer2/tests/test_util.py new file mode 100644 index 0000000000000000000000000000000000000000..d9862343f6055608d63e5a3df902f755174af2d1 --- /dev/null +++ b/pyminer2/tests/test_util.py @@ -0,0 +1,160 @@ +import os +import unittest +import warnings + +import numpy as np +import scipy.sparse as sp + +from Orange.util import export_globals, flatten, deprecated, try_, deepgetattr, \ + OrangeDeprecationWarning +from Orange.data import Table +from Orange.data.util import vstack, hstack, array_equal +from Orange.statistics.util import stats +from Orange.tests.test_statistics import dense_sparse + +SOMETHING = 0xf00babe + + +class TestUtil(unittest.TestCase): + def test_export_globals(self): + self.assertEqual(sorted(export_globals(globals(), __name__)), + ['SOMETHING', 'TestUtil']) + + def test_flatten(self): + self.assertEqual(list(flatten([[1, 2], [3]])), [1, 2, 3]) + + def test_deprecated(self): + @deprecated + def identity(x): + return x + + with self.assertWarns(DeprecationWarning) as cm: + x = identity(10) + self.assertEqual(x, 10) + self.assertTrue('deprecated' in cm.warning.args[0]) + self.assertTrue('identity' in cm.warning.args[0]) + + def test_try_(self): + self.assertTrue(try_(lambda: np.ones(3).any())) + self.assertFalse(try_(lambda: np.whatever())) + self.assertEqual(try_(len, default=SOMETHING), SOMETHING) + + def test_reprable(self): + from Orange.data import ContinuousVariable + from Orange.preprocess.impute import ReplaceUnknownsRandom + from Orange.statistics.distribution import Continuous + from Orange.classification import LogisticRegressionLearner + + var = ContinuousVariable('x') + transform = ReplaceUnknownsRandom(var, Continuous(1, var)) + + self.assertEqual(repr(transform).replace('\n', '').replace(' ', ''), + "ReplaceUnknownsRandom(" + "variable=ContinuousVariable(name='x',number_of_decimals=3)," + "distribution=Continuous([[0.],[0.]]))") + + # GH 2275 + logit = LogisticRegressionLearner() + for _ in range(2): + self.assertEqual(repr(logit), 'LogisticRegressionLearner()') + + def test_deepgetattr(self): + class a: + l = [] + self.assertTrue(deepgetattr(a, 'l.__len__.__call__'), a.l.__len__.__call__) + self.assertTrue(deepgetattr(a, 'l.__nx__.__x__', 42), 42) + self.assertRaises(AttributeError, lambda: deepgetattr(a, 'l.__nx__.__x__')) + + def test_vstack(self): + numpy = np.array([[1., 2.], [3., 4.]]) + csr = sp.csr_matrix(numpy) + csc = sp.csc_matrix(numpy) + + self.assertCorrectArrayType( + vstack([numpy, numpy]), + shape=(4, 2), sparsity="dense") + self.assertCorrectArrayType( + vstack([csr, numpy]), + shape=(4, 2), sparsity="sparse") + self.assertCorrectArrayType( + vstack([numpy, csc]), + shape=(4, 2), sparsity="sparse") + self.assertCorrectArrayType( + vstack([csc, csr]), + shape=(4, 2), sparsity="sparse") + + def test_hstack(self): + numpy = np.array([[1., 2.], [3., 4.]]) + csr = sp.csr_matrix(numpy) + csc = sp.csc_matrix(numpy) + + self.assertCorrectArrayType( + hstack([numpy, numpy]), + shape=(2, 4), sparsity="dense") + self.assertCorrectArrayType( + hstack([csr, numpy]), + shape=(2, 4), sparsity="sparse") + self.assertCorrectArrayType( + hstack([numpy, csc]), + shape=(2, 4), sparsity="sparse") + self.assertCorrectArrayType( + hstack([csc, csr]), + shape=(2, 4), sparsity="sparse") + + def assertCorrectArrayType(self, array, shape, sparsity): + self.assertEqual(array.shape, shape) + self.assertEqual(["dense", "sparse"][sp.issparse(array)], sparsity) + + @unittest.skipUnless(os.environ.get('ORANGE_DEPRECATIONS_ERROR'), + 'ORANGE_DEPRECATIONS_ERROR not set') + def test_raise_deprecations(self): + with self.assertRaises(OrangeDeprecationWarning): + warnings.warn('foo', OrangeDeprecationWarning) + + def test_stats_sparse(self): + """ + Stats should not fail when trying to calculate mean on sparse data. + GH-2357 + """ + data = Table("iris") + sparse_x = sp.csr_matrix(data.X) + self.assertTrue(stats(data.X).all() == stats(sparse_x).all()) + + @dense_sparse + def test_array_equal(self, array): + a1 = array([[0., 2.], [3., np.nan]]) + a2 = array([[0., 2.], [3., np.nan]]) + self.assertTrue(array_equal(a1, a2)) + + a3 = np.array([[0., 2.], [3., np.nan]]) + self.assertTrue(array_equal(a1, a3)) + self.assertTrue(array_equal(a3, a1)) + + @dense_sparse + def test_array_not_equal(self, array): + a1 = array([[0., 2.], [3., np.nan]]) + a2 = array([[0., 2.], [4., np.nan]]) + self.assertFalse(array_equal(a1, a2)) + + a3 = array([[0., 2.], [3., np.nan], [4., 5.]]) + self.assertFalse(array_equal(a1, a3)) + + def test_csc_array_equal(self): + a1 = sp.csc_matrix(([1, 4, 5], ([0, 0, 1], [0, 2, 2])), shape=(2, 3)) + a2 = sp.csc_matrix(([5, 1, 4], ([1, 0, 0], [2, 0, 2])), shape=(2, 3)) + a2[0, 1] = 0 # explicitly setting to 0 + self.assertTrue(array_equal(a1, a2)) + + def test_csc_scr_equal(self): + a1 = sp.csc_matrix(([1, 4, 5], ([0, 0, 1], [0, 2, 2])), shape=(2, 3)) + a2 = sp.csr_matrix(([5, 1, 4], ([1, 0, 0], [2, 0, 2])), shape=(2, 3)) + self.assertTrue(array_equal(a1, a2)) + + a1 = sp.csc_matrix(([1, 4, 5], ([0, 0, 1], [0, 2, 2])), shape=(2, 3)) + a2 = sp.csr_matrix(([1, 4, 5], ([0, 0, 1], [0, 2, 2])), shape=(2, 3)) + self.assertTrue(array_equal(a1, a2)) + + def test_csc_unordered_array_equal(self): + a1 = sp.csc_matrix(([1, 4, 5], [0, 0, 1], [0, 1, 1, 3]), shape=(2, 3)) + a2 = sp.csc_matrix(([1, 5, 4], [0, 1, 0], [0, 1, 1, 3]), shape=(2, 3)) + self.assertTrue(array_equal(a1, a2)) diff --git a/pyminer2/tests/test_value.py b/pyminer2/tests/test_value.py new file mode 100644 index 0000000000000000000000000000000000000000..20e09dff9471b494e37baeeae59fcd6fb544c7f1 --- /dev/null +++ b/pyminer2/tests/test_value.py @@ -0,0 +1,66 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import pickle +import unittest +import numpy as np + +from Orange.data import Table, Domain, Value,\ + DiscreteVariable, ContinuousVariable, StringVariable, TimeVariable + + +class TestValue(unittest.TestCase): + def test_pickling_discrete_values(self): + iris = Table('iris') + + a = iris[0]['iris'] + b = pickle.loads(pickle.dumps(a)) + + self.assertEqual(float(a), float(b)) + self.assertEqual(a.value, b.value) + + def test_pickling_string_values(self): + zoo = Table('zoo') + + a = zoo[0]['name'] + b = pickle.loads(pickle.dumps(a)) + + self.assertEqual(float(a), float(b)) + self.assertEqual(a.value, b.value) + + def test_compare_continuous(self): + auto = Table('housing') + acc1 = auto[0]['MEDV'] # 24.0 + acc2 = auto[1]['MEDV'] # 21.6 + self.assertTrue(acc1 > acc2) + self.assertTrue(acc1 >= 24.0) + self.assertFalse(acc1 != acc1) + + def test_compare_discrete(self): + data = Table(Domain([DiscreteVariable(name="G", values=["M", "F"])]), + np.array([[0], [1]])) + self.assertTrue(data[0]['G'] < data[1]['G']) + self.assertTrue(data[0]['G'] >= data[0]['G']) + self.assertTrue(data[0]['G'] < 1) + self.assertTrue(data[0]['G'] < "F") + self.assertFalse(data[1]['G'] < "F") + + def test_compare_string(self): + zoo = Table('zoo') + zoo1 = zoo[0]['name'] # aardvark + zoo2 = zoo[1]['name'] # antelope + self.assertTrue(zoo1 < zoo2) + self.assertTrue(zoo1 >= "aardvark") + + def test_hash(self): + v = 1234.5 + val = Value(ContinuousVariable("var"), v) + self.assertTrue(val == v and hash(val) == hash(v)) + v = "test" + val = Value(StringVariable("var"), v) + self.assertTrue(val == v and hash(val) == hash(v)) + v = 1234.5 + val = Value(TimeVariable("var"), v) + self.assertTrue(val == v and hash(val) == hash(v)) + val = Value(DiscreteVariable("var", ["red", "green", "blue"]), 1) + self.assertRaises(TypeError, hash, val) diff --git a/pyminer2/tests/test_xlsx_reader.py b/pyminer2/tests/test_xlsx_reader.py new file mode 100644 index 0000000000000000000000000000000000000000..21e3c0021d26135a4dfbce19693c9aac131187b4 --- /dev/null +++ b/pyminer2/tests/test_xlsx_reader.py @@ -0,0 +1,185 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring + +import unittest +import os +from functools import wraps +from typing import Callable + +import numpy as np + +from Orange.data import io, ContinuousVariable, DiscreteVariable, Table + + +def get_dataset(name): + return os.path.join(os.path.dirname(__file__), "xlsx_files", name) + + +def get_xlsx_reader(name: str) -> io.ExcelReader: + return io.ExcelReader(get_dataset(name)) + + +def get_xls_reader(name: str) -> io.XlsReader: + return io.XlsReader(get_dataset(name)) + + +def read_file(reader: Callable, name: str) -> Table: + return reader(name).read() + + +def test_xlsx_xls(f): + @wraps(f) + def wrapper(self): + f(self, get_xlsx_reader) + f(self, get_xls_reader) + return wrapper + + +class TestExcelReader(unittest.TestCase): + def test_read_round_floats(self): + table = read_file(get_xlsx_reader, "round_floats.xlsx") + domain = table.domain + self.assertIsNone(domain.class_var) + self.assertEqual(len(domain.metas), 0) + self.assertEqual(len(domain.attributes), 3) + self.assertIsInstance(domain[0], ContinuousVariable) + self.assertIsInstance(domain[1], ContinuousVariable) + self.assertListEqual(domain[2].values, ["1", "2"]) + + +class TestExcelHeader0(unittest.TestCase): + @test_xlsx_xls + def test_read(self, reader: Callable[[str], io.FileFormat]): + table = read_file(reader, "header_0.xlsx") + domain = table.domain + self.assertIsNone(domain.class_var) + self.assertEqual(len(domain.metas), 0) + self.assertEqual(len(domain.attributes), 4) + for i, var in enumerate(domain.attributes): + self.assertIsInstance(var, ContinuousVariable) + self.assertEqual(var.name, "Feature {}".format(i + 1)) + np.testing.assert_almost_equal(table.X, + np.array([[0.1, 0.5, 0.1, 21], + [0.2, 0.1, 2.5, 123], + [0, 0, 0, 0]])) + self.assertEqual(table.name, 'header_0') + + +class TextExcelSheets(unittest.TestCase): + @test_xlsx_xls + def test_sheets(self, reader: Callable[[str], io.FileFormat]): + reader = reader("header_0_sheet.xlsx") + self.assertSequenceEqual(reader.sheets, + ["Sheet1", "my_sheet", "Sheet3"]) + + @test_xlsx_xls + def test_named_sheet(self, reader: Callable[[str], io.FileFormat]): + reader = reader("header_0_sheet.xlsx") + reader.select_sheet("my_sheet") + table = reader.read() + self.assertEqual(len(table.domain.attributes), 4) + self.assertEqual(table.name, 'header_0_sheet-my_sheet') + + def test_named_sheet_table_xlsx(self): + table = Table.from_file(get_dataset("header_0_sheet.xlsx"), + sheet="my_sheet") + self.assertEqual(len(table.domain.attributes), 4) + self.assertEqual(table.name, 'header_0_sheet-my_sheet') + + def test_named_sheet_table_xls(self): + table = Table.from_file(get_dataset("header_0_sheet.xls"), + sheet="my_sheet") + self.assertEqual(len(table.domain.attributes), 4) + self.assertEqual(table.name, 'header_0_sheet-my_sheet') + + +class TestExcelHeader1(unittest.TestCase): + @test_xlsx_xls + def test_no_flags(self, reader: Callable[[str], io.FileFormat]): + table = read_file(reader, "header_1_no_flags.xlsx") + domain = table.domain + self.assertEqual(len(domain.metas), 0) + self.assertEqual(len(domain.attributes), 4) + self.assertIsInstance(domain[0], DiscreteVariable) + self.assertIsInstance(domain[1], ContinuousVariable) + self.assertIsInstance(domain[2], DiscreteVariable) + self.assertIsInstance(domain[3], ContinuousVariable) + for i, var in enumerate(domain.variables): + self.assertEqual(var.name, chr(97 + i)) + self.assertEqual(domain[0].values, ["green", "red"]) + np.testing.assert_almost_equal(table.X, + np.array([[1, 0.5, 0, 21], + [1, 0.1, 0, 123], + [0, 0, np.nan, 0]])) + np.testing.assert_equal(table.Y, np.array([]).reshape(3, 0)) + + @test_xlsx_xls + def test_flags(self, reader: Callable[[str], io.FileFormat]): + table = read_file(reader, "header_1_flags.xlsx") + domain = table.domain + + self.assertEqual(len(domain.attributes), 1) + attr = domain.attributes[0] + self.assertEqual(attr.name, "d") + self.assertIsInstance(attr, ContinuousVariable) + np.testing.assert_almost_equal(table.X, np.arange(23).reshape(23, 1)) + + self.assertEqual(len(domain.class_vars), 1) + class_ = domain.class_var + self.assertEqual(class_.name, "b") + self.assertIsInstance(class_, ContinuousVariable) + np.testing.assert_almost_equal( + table.Y, np.array([.5, .1, 0, 0] * 5 + [.5, .1, 0])) + + self.assertEqual(len(domain.metas), 3) + for n, var in zip("acf", domain.metas): + self.assertEqual(var.name, n) + self.assertIsInstance(domain.metas[0], DiscreteVariable) + self.assertEqual(domain.metas[0].values, ["green", "red"]) + self.assertIsInstance(domain.metas[1], ContinuousVariable) + np.testing.assert_almost_equal( + table.metas[:, 0], np.array([1, 1, 0] * 7 + [1, 1])) + np.testing.assert_almost_equal( + table.metas[:, 1], np.array([0, 1, 2, 3] * 5 + [0, 1, 2])) + + +class TestExcelHeader3(unittest.TestCase): + @test_xlsx_xls + def test_read(self, reader: Callable[[str], io.FileFormat]): + table = read_file(reader, "header_3.xlsx") + domain = table.domain + + self.assertEqual(len(domain.attributes), 2) + attr = domain.attributes[0] + self.assertEqual(attr.name, "d") + self.assertIsInstance(attr, ContinuousVariable) + np.testing.assert_almost_equal(table.X[:, 0], np.arange(23)) + attr = domain.attributes[1] + self.assertEqual(attr.name, "g") + self.assertIsInstance(attr, DiscreteVariable) + np.testing.assert_almost_equal(table.X[:, 1], + np.array([1, 0] + [float("nan")] * 21)) + + self.assertEqual(len(domain.class_vars), 1) + class_ = domain.class_var + self.assertEqual(class_.name, "b") + self.assertIsInstance(class_, ContinuousVariable) + np.testing.assert_almost_equal( + table.Y, np.array([.5, .1, 0, 0] * 5 + [.5, .1, 0])) + + self.assertEqual(len(domain.metas), 3) + for n, var in zip("acf", domain.metas): + self.assertEqual(var.name, n) + self.assertIsInstance(domain.metas[0], DiscreteVariable) + self.assertEqual(domain.metas[0].values, ["green", "red"]) + self.assertIsInstance(domain.metas[1], ContinuousVariable) + np.testing.assert_almost_equal( + table.metas[:, 0], np.array([1, 1, 0] * 7 + [1, 1])) + np.testing.assert_almost_equal( + table.metas[:, 1], np.array([0, 1, 2, 3] * 5 + [0, 1, 2])) + np.testing.assert_equal( + table.metas[:, 2], np.array(list("abcdefghijklmnopqrstuvw"))) + + +if __name__ == "__main__": + unittest.main() diff --git a/pyminer2/tests/xlsx_files/header_0.xlsx b/pyminer2/tests/xlsx_files/header_0.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f8516ac5db28cee454b82903d781d811db1ae07b Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_0.xlsx differ diff --git a/pyminer2/tests/xlsx_files/header_0_sheet.xls b/pyminer2/tests/xlsx_files/header_0_sheet.xls new file mode 100644 index 0000000000000000000000000000000000000000..1cf0a913579c70a19360255f6cc2fe734632e447 Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_0_sheet.xls differ diff --git a/pyminer2/tests/xlsx_files/header_0_sheet.xlsx b/pyminer2/tests/xlsx_files/header_0_sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3b5a68de577e620a2e49101f567daa102f6143d3 Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_0_sheet.xlsx differ diff --git a/pyminer2/tests/xlsx_files/header_1_flags.xlsx b/pyminer2/tests/xlsx_files/header_1_flags.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a9ffa46b6beaa0f59e284794dbbc326e5cfb7ec7 Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_1_flags.xlsx differ diff --git a/pyminer2/tests/xlsx_files/header_1_no_flags.xlsx b/pyminer2/tests/xlsx_files/header_1_no_flags.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..38422e3f37b38af7e65d4e2324ace9e58b9adfbe Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_1_no_flags.xlsx differ diff --git a/pyminer2/tests/xlsx_files/header_3.xlsx b/pyminer2/tests/xlsx_files/header_3.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..32b75aa08a43eb9ac0da33bb5d0337dc8d4584e4 Binary files /dev/null and b/pyminer2/tests/xlsx_files/header_3.xlsx differ diff --git a/pyminer2/tests/xlsx_files/round_floats.xlsx b/pyminer2/tests/xlsx_files/round_floats.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9ddb5caf3c546434dcbd7237b45ff920089ba077 Binary files /dev/null and b/pyminer2/tests/xlsx_files/round_floats.xlsx differ diff --git a/readme_figures/app2-plot.png b/readme_figures/app2-plot.png deleted file mode 100644 index 9a8a632cc0ad0ef5fe52c72171bbc0726c17f14d..0000000000000000000000000000000000000000 Binary files a/readme_figures/app2-plot.png and /dev/null differ diff --git a/readme_figures/app2-table.png b/readme_figures/app2-table.png deleted file mode 100644 index a5ddfd6f863c667cf7d04fa9d6e670fdd998aa62..0000000000000000000000000000000000000000 Binary files a/readme_figures/app2-table.png and /dev/null differ diff --git a/readme_figures/app2.png b/readme_figures/app2.png deleted file mode 100644 index dd0be3bee3ace16a7bb63c527f4f377ac4f94700..0000000000000000000000000000000000000000 Binary files a/readme_figures/app2.png and /dev/null differ diff --git a/requirements_linux.txt b/requirements_linux.txt deleted file mode 100644 index 188c634c0e50d7751c9c72674488cdb13fde104a..0000000000000000000000000000000000000000 --- a/requirements_linux.txt +++ /dev/null @@ -1,39 +0,0 @@ -certifi==2020.6.20 -cycler==0.10.0 -et-xmlfile==1.0.1 -helpdev==0.7.1 -jdcal==1.4.1 -joblib==0.16.0 -kiwisolver==1.2.0 -matplotlib==3.3.1 -numpy==1.19.1 -openpyxl==3.0.4 -pandas==1.1.1 -Pillow==7.2.0 -PyMySQL==0.10.0 -pyparsing==2.4.7 -PyQt5==5.15.0 -PyQt5-sip==12.8.0 -pyreadstat==1.0.1 -python-dateutil==2.8.1 -pytz==2020.1 -QDarkStyle==2.8.1 -QtPy==1.9.0 -scikit-learn==0.23.2 -scipy==1.5.2 -six==1.15.0 -threadpoolctl==2.1.0 -xlrd==1.2.0 -qtconsole==4.7.7 -pretty_errors -json-rpc==1.13.0 -Werkzeug==1.0.1 -requests==2.24.0 -tornado==6.0.4 -jedi==0.17.2 -dill==0.3.2 -matgen>=0.1.1 -QScintilla==2.11.5 -yapf -flake8 -configparser \ No newline at end of file diff --git a/requirements_mac.txt b/requirements_mac.txt deleted file mode 100644 index 188c634c0e50d7751c9c72674488cdb13fde104a..0000000000000000000000000000000000000000 --- a/requirements_mac.txt +++ /dev/null @@ -1,39 +0,0 @@ -certifi==2020.6.20 -cycler==0.10.0 -et-xmlfile==1.0.1 -helpdev==0.7.1 -jdcal==1.4.1 -joblib==0.16.0 -kiwisolver==1.2.0 -matplotlib==3.3.1 -numpy==1.19.1 -openpyxl==3.0.4 -pandas==1.1.1 -Pillow==7.2.0 -PyMySQL==0.10.0 -pyparsing==2.4.7 -PyQt5==5.15.0 -PyQt5-sip==12.8.0 -pyreadstat==1.0.1 -python-dateutil==2.8.1 -pytz==2020.1 -QDarkStyle==2.8.1 -QtPy==1.9.0 -scikit-learn==0.23.2 -scipy==1.5.2 -six==1.15.0 -threadpoolctl==2.1.0 -xlrd==1.2.0 -qtconsole==4.7.7 -pretty_errors -json-rpc==1.13.0 -Werkzeug==1.0.1 -requests==2.24.0 -tornado==6.0.4 -jedi==0.17.2 -dill==0.3.2 -matgen>=0.1.1 -QScintilla==2.11.5 -yapf -flake8 -configparser \ No newline at end of file diff --git a/update_requirement.bat b/update_requirement.bat deleted file mode 100644 index bcee78e58ef74a554ace24804644b6a50bd28009..0000000000000000000000000000000000000000 --- a/update_requirement.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -rem 运行后可以直接更新需要的依赖关系 -set road=%~dp0 -set file=requirements.txt -set road_file=%road%%file% -pip install -i https://mirrors.cloud.tencent.com/pypi/simple -r %road_file% -pause \ No newline at end of file