├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── Makefile ├── make.bat └── source │ ├── Algorithm.md │ ├── Collect-Data.md │ ├── Feature-Engineering.md │ ├── Quick-Start.md │ ├── Rule-Setting.md │ ├── conf.py │ ├── imgs │ ├── algorithm │ │ ├── 01.png │ │ └── 02.png │ ├── feature_engineering │ │ ├── feature_dev_order1.png │ │ ├── feature_dev_order1_x.png │ │ ├── feature_dev_order2.png │ │ ├── feature_doa.png │ │ └── trace_answer_unlock.png │ └── quick_start │ │ ├── selenium_jump.png │ │ ├── selenium_jump_browser.png │ │ ├── trace_itmorn.png │ │ └── trace_itmorn_browser.png │ ├── index.rst │ ├── mouse_track │ ├── index.rst │ └── mouse_track.rst │ └── risk_motion │ ├── index.rst │ ├── motion_constant_velocity.rst │ ├── motion_jump.rst │ ├── motion_linear.rst │ ├── motion_similar.rst │ ├── motion_slow.rst │ └── motion_vertical_horizontal_linear.rst ├── examples ├── collect_data.html ├── example_feature_vis.py ├── example_motion_jump.py ├── example_rules.py ├── server.py ├── trace_examples.py └── use_selenium_jump.py ├── imgs └── contacts.jpg ├── requirements.txt ├── robot_mouse_track ├── contants.py ├── mouse_track.py ├── risk_motion │ ├── motion_constant_velocity.py │ ├── motion_jump.py │ ├── motion_linear.py │ ├── motion_similar.py │ ├── motion_slow.py │ └── motion_vertical_horizontal_linear.py └── utils.py ├── setup.py └── tests ├── __init__.py ├── risk_motion ├── __init__.py ├── test_motion_constant_velocity.py ├── test_motion_jump.py ├── test_motion_linear.py ├── test_motion_similar.py ├── test_motion_slow.py └── test_motion_vertical_horizontal_linear.py └── test_mouse_track.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the "main" branch 8 | push: 9 | branches: [ "main" ] 10 | pull_request: 11 | branches: [ "main" ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | build: 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | # Steps represent a sequence of tasks that will be executed as part of the job 24 | steps: 25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 26 | - uses: actions/checkout@v3 27 | 28 | # Runs a single command using the runners shell 29 | - name: Install requirements 30 | run: pip install -r requirements.txt 31 | - name: Run tests and collect coverage 32 | run: | 33 | pytest --cov --cov-report=html 34 | 35 | # Runs a set of commands using the runners shell 36 | - name: Run a multi-line script 37 | run: | 38 | curl -Os https://uploader.codecov.io/latest/linux/codecov 39 | chmod +x codecov 40 | ./codecov -t ${{secrets.CODECOV_TOKEN}} 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | doc/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | /.idea 131 | /tst.py 132 | /history/ 133 | /bash.txt 134 | /examples/collect_data_ap.html 135 | /examples/server_ap.py 136 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # robot-mouse-track 2 | [![Python Versions](https://img.shields.io/pypi/pyversions/robot-mouse-track)](https://pypi.org/project/robot-mouse-track) 3 | [![PyPI Version](https://img.shields.io/pypi/v/robot-mouse-track)](https://pypi.org/project/robot-mouse-track) 4 | [![Downloads](https://pepy.tech/badge/robot-mouse-track)](https://pepy.tech/project/robot-mouse-track) 5 | [![Disscussion](https://img.shields.io/badge/chat-wechat-brightgreen?style=flat)](./README.md#讨论交流) 6 | 7 | [![Documentation Status](https://readthedocs.org/projects/robot-mouse-track/badge/?version=latest)](https://robot-mouse-track.readthedocs.io/zh/latest/?badge=latest) 8 | [![CI status](https://github.com/itmorn/robot-mouse-track/actions/workflows/main.yml/badge.svg)](https://github.com/itmorn/robot-mouse-track/actions) 9 | [![codecov](https://codecov.io/gh/itmorn/robot-mouse-track/branch/main/graph/badge.svg)](https://codecov.io/gh/itmorn/robot-mouse-track) 10 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/873baeb256bd4f1cbcf7f516897a3415)](https://www.codacy.com/gh/itmorn/robot-mouse-track/dashboard?utm_source=github.com&utm_medium=referral&utm_content=itmorn/robot-mouse-track&utm_campaign=Badge_Grade) 11 | [![License](https://img.shields.io/github/license/itmorn/robot-mouse-track.svg)](https://github.com/itmorn/robot-mouse-track/blob/main/LICENSE) 12 | 13 | 随着互联网技术的发展,鼠标轨迹识别算法在很多人机交互产品中的需求日益增加, 14 | 比如,一些网站为了防止被爬,增加了一些滑块验证码,但是一些软件已经可以模拟人的行为破解滑块验证码。 15 | 本项目就是通过对鼠标轨迹的特征分析,判定是否是人的行为还是机器行为。常见应用场景:网站反爬虫、在线考试系统脚本刷题。 16 | 17 | ## 文档 18 | https://robot-mouse-track.readthedocs.io 19 | 20 | ## 讨论交流 21 | ![img.png](imgs/contacts.jpg) -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/Algorithm.md: -------------------------------------------------------------------------------- 1 | # 算法原理 2 | 3 | ## 速度的计算 4 | ![](imgs/algorithm/01.png) 5 | 我们知道,要想计算速度,必须要有距离s和时间t. 6 | 7 | 点1到点2之间的平均速度,既可以当做点1位置的瞬时速度,也可以当做点2位置的瞬时速度。 8 | 9 | 这里,不失一般性,我们把计算出来的值都归到起点位置,这样可以简化问题。 10 | 11 | 假设鼠标轨迹点有n个,那么速度序列就应该有n-1个,加速度序列就有n-2个,依次类推。 12 | 13 | ## 速度为0,可能仍在运动! 14 | 还是以上图为例,假设正在使用selenium的moveto操控浏览器。 15 | 16 | 先从点1跳到点2,然后原地sleep 12小时,再跳到点3,那么计算点2的速度就接近于0, 17 | 这就出现了漏检鼠标跳变的问题。 18 | 19 | 为了解决这个问题,我们对两点之间的时间差做了截断 20 | 21 | ```python 22 | self._arr_diff_time = np.clip(self._arr_diff_dis[:, -1:], 0, self.max_duration_silent) 23 | ``` 24 | 25 | 这样,即使存在睡眠的情况,也会计算出一个高速的移动。 26 | 27 | 28 | ## 方向角的计算 29 | ![](imgs/algorithm/02.png) 30 | 我们在计算方向角的时候,尽量避免使用连续的两个点,因为那样很容易出现大量45度,90度的现象, 31 | 不利于我们分析问题。 32 | 33 | 我们采用的方法为计算一定间隔的两点之间的角度,当作其起点位置的方向角,对应代码如下: 34 | ```python 35 | arr_diff_dis = self.arr_trace[self.max_doa_point:, :-1] - self.arr_trace[:-self.max_doa_point, :-1] 36 | ``` 37 | 38 | 当方向角正切值等于无穷的时候,还需做截断: 39 | ```python 40 | np.clip(arr_diff_dis[:, 1] / arr_diff_dis[:, 0], -self.max_doa_tan, self.max_doa_tan) 41 | ``` 42 | 43 | ## 轨迹向量化 44 | 轨迹向量化的目的是为了计算轨迹间的相似度。 45 | 这里我们需要考虑的问题包括: 46 | - 具备一定容错性 47 | - 存储开销不可过大 48 | - 计算相似度的方法高效 49 | - 具备一定可解释性 50 | 51 | 我们采用的是直方图的方法,采用分桶的机制进行像素级别的容错。 52 | 具体代码见 [API](risk_motion/motion_similar.html#robot_mouse_track.risk_motion.motion_similar.calc_vec) 53 | 54 | 55 | ## 轨迹向量间的相似度计算 56 | 计算向量之间相似度的方法采用的是计算分布之间的绝对值距离, 57 | 该算法比起JS散度,计算更高效且可解释性强。 58 | 具体代码见 [API](risk_motion/motion_similar.html#robot_mouse_track.risk_motion.motion_similar.SimilarMotion.judge_risk) -------------------------------------------------------------------------------- /docs/source/Collect-Data.md: -------------------------------------------------------------------------------- 1 | # 鼠标轨迹数据的收集 2 | 3 | ## 浏览器端 4 | 在代码仓库中,我们提供了一个前端页面,其使用document.onmousemove监听鼠标的移动, 5 | 当点击提交之后,会将收集到的鼠标轨迹序列通过Ajax的方式发送给服务器端, 6 | 对应代码为:[collect_data.html](https://github.com/itmorn/robot-mouse-track/blob/main/examples/collect_data.html) 7 | 8 | ## 服务器端 9 | 服务器端采用了flask部署了一个微服务,可以打印收集到的轨迹,方便我们进行记录和分析, 10 | 对应代码为:[server.py](https://github.com/itmorn/robot-mouse-track/blob/main/examples/server.py) 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/source/Feature-Engineering.md: -------------------------------------------------------------------------------- 1 | # 特征工程 2 | 3 | ## 业务分析 4 | 经过调研,我们可以将带有以下特征的鼠标轨迹判定为机器轨迹: 5 | - 跳变运动(鼠标由一个点直接跳到很远的另一个点)【实现】 6 | - 横/竖直线运动(人手可能会画出横/竖直线,但是很难画出非常长的横/竖直线)【实现】 7 | - 斜直线运动(人手可能会画出横/竖直线,但是画不出来斜直线)【实现】 8 | - 分速度的匀速运动【实现】 9 | - 分速度的匀变速运动【实现】 10 | - 分速度的匀变加速运动【实现】 11 | - 合速度的匀速运动【实现】 12 | - 合速度的匀变速运动【实现】 13 | - 合速度的匀变加速运动【实现】 14 | - 轨迹点间 时间间隔非常大的运动(比如pyautogui、鼠标录制软件【普通速度】)【实现】 15 | - 轨迹点间 时间间隔远偏离均值的运动(鼠标录制软件【适当加速】)同上 16 | - 轨迹点间 时间间隔非常小,但是运动速度和加速度非常大的运动(鼠标录制软件【高速】)可以视为跳变 17 | - 路径重复的运动(防止一些未知的鼠标录制软件可以躲过以上防御,这里可以加最后一层防御)【实现】 18 | 19 | 爬虫和反爬虫是一个对抗的过程,如果大家还有其他的想法,欢迎补充 20 | 21 | ## 特征提取 22 | 经过调研和业务分析,我们抽取了以下特征: 23 | - 鼠标移动速度 24 | - 鼠标移动加速度(二阶速度) 25 | - 鼠标移动n阶速度 26 | - 鼠标移动分速度 27 | - 鼠标移动分加速度(二阶速度) 28 | - 鼠标移动分n阶速度 29 | - 鼠标移动方向角的变化 30 | - 鼠标轨迹点之间的时间间隔 31 | - 鼠标轨迹的向量化(可用来计算轨迹间的相似度) 32 | 33 | 通过这些特征的提取,基本可以覆盖到我们的业务需求 34 | 35 | ## 可视化 36 | ### 鼠标轨迹展示 37 | ```python 38 | trace_answer_unlock = [[72, 0, 1655046417887], [72, 1, 1655046417903], [70, 3, 1655046417916], [69, 5, 1655046417930], [68, 6, 1655046417951], [67, 8, 1655046417983], [67, 10, 1655046417996], [65, 15, 1655046418010], [62, 20, 1655046418023], [61, 23, 1655046418036], [59, 26, 1655046418049], [59, 27, 1655046418063], [57, 29, 1655046418076], [55, 31, 1655046418089], [54, 32, 1655046418103], [52, 34, 1655046418116], [49, 38, 1655046418129], [46, 40, 1655046418143], [42, 45, 1655046418156], [37, 50, 1655046418170], [34, 53, 1655046418183], [33, 55, 1655046418196], [30, 56, 1655046418210], [27, 57, 1655046418223], [27, 58, 1655046418236], [26, 58, 1655046418250], [24, 60, 1655046418263], [22, 63, 1655046418276], [19, 67, 1655046418290], [19, 68, 1655046418303], [18, 70, 1655046418316], [17, 71, 1655046418330], [17, 72, 1655046418345], [17, 73, 1655046418361], [17, 74, 1655046418435], [15, 75, 1655046418463], [13, 76, 1655046418476], [12, 77, 1655046418490], [11, 77, 1655046418503], [9, 78, 1655046418516], [9, 79, 1655046418530], [8, 79, 1655046418543], [7, 79, 1655046418583], [7, 80, 1655046418596], [7, 81, 1655046418818], [7, 84, 1655046418828], [7, 88, 1655046418836], [7, 94, 1655046418850], [6, 94, 1655046419230], [6, 95, 1655046419238], [5, 95, 1655046419249], [5, 96, 1655046419263], [5, 97, 1655046419276], [5, 103, 1655046419289], [5, 106, 1655046419303], [5, 108, 1655046419316], [5, 114, 1655046419330], [5, 121, 1655046419343], [5, 124, 1655046419356], [5, 131, 1655046419369], [6, 137, 1655046419383], [6, 139, 1655046419396], [6, 148, 1655046419409], [6, 150, 1655046419423], [7, 154, 1655046419436], [8, 157, 1655046419450], [8, 159, 1655046419463], [8, 162, 1655046419476], [8, 165, 1655046419489], [8, 167, 1655046419503], [9, 169, 1655046419516], [9, 171, 1655046419530], [9, 173, 1655046419543], [9, 175, 1655046419556], [9, 179, 1655046419570], [9, 180, 1655046419583], [9, 184, 1655046419596], [9, 188, 1655046419610], [9, 190, 1655046419623], [9, 194, 1655046419636], [9, 197, 1655046419650], [9, 198, 1655046419671], [9, 199, 1655046419688], [9, 200, 1655046419705], [9, 201, 1655046419716], [9, 202, 1655046419730], [9, 203, 1655046419745], [9, 204, 1655046419769], [9, 205, 1655046419793], [9, 206, 1655046419801], [9, 208, 1655046419809], [9, 209, 1655046419823], [9, 212, 1655046419836], [10, 214, 1655046419850], [10, 215, 1655046419863], [10, 216, 1655046419877], [11, 216, 1655046419890], [11, 217, 1655046419903], [11, 218, 1655046419916], [11, 219, 1655046419930], [11, 220, 1655046420560], [11, 221, 1655046420571], [12, 227, 1655046420583], [12, 230, 1655046420597], [13, 236, 1655046420610], [13, 241, 1655046420623], [13, 242, 1655046420637], [13, 245, 1655046420650], [13, 250, 1655046420663], [13, 253, 1655046420677], [13, 258, 1655046420690], [12, 264, 1655046420703], [12, 266, 1655046420717], [11, 269, 1655046420730], [11, 271, 1655046420744], [10, 274, 1655046420757], [10, 277, 1655046420770], [9, 282, 1655046420783], [9, 285, 1655046420797], [9, 291, 1655046420810], [8, 299, 1655046420823], [8, 302, 1655046420837], [8, 308, 1655046420850], [8, 314, 1655046420863], [8, 318, 1655046420877], [8, 322, 1655046420890], [8, 325, 1655046420904], [8, 328, 1655046420918], [8, 331, 1655046420931], [8, 334, 1655046420944], [8, 337, 1655046420958], [8, 339, 1655046420971], [8, 341, 1655046420984], [8, 343, 1655046420998], [8, 344, 1655046421013], [8, 345, 1655046421025], [8, 347, 1655046421038], [8, 348, 1655046421051], [8, 350, 1655046421064], [8, 352, 1655046421078], [8, 353, 1655046421092], [8, 355, 1655046421104], [8, 356, 1655046421118], [8, 359, 1655046421131], [9, 362, 1655046421145], [9, 366, 1655046421158], [9, 367, 1655046421171], [9, 369, 1655046421184], [9, 371, 1655046421198], [9, 372, 1655046421221], [9, 373, 1655046421342], [11, 373, 1655046421837], [21, 375, 1655046421865], [32, 377, 1655046421878], [49, 382, 1655046421892], [62, 386, 1655046421905], [92, 398, 1655046421918], [109, 410, 1655046421931], [145, 436, 1655046421945], [175, 452, 1655046421959], [214, 476, 1655046421972], [231, 486, 1655046421985], [277, 506, 1655046421998], [332, 524, 1655046422012], [358, 530, 1655046422025], [401, 540, 1655046422039], [461, 554, 1655046422052], [484, 559, 1655046422065], [537, 569, 1655046422078], [579, 574, 1655046422092], [599, 575, 1655046422106], [611, 576, 1655046422118], [637, 576, 1655046422132], [656, 577, 1655046422145], [666, 577, 1655046422158], [679, 578, 1655046422173], [695, 579, 1655046422186], [701, 579, 1655046422198], [712, 579, 1655046422211], [721, 579, 1655046422225], [723, 579, 1655046422239], [729, 579, 1655046422251], [733, 579, 1655046422265], [734, 580, 1655046422278], [736, 580, 1655046422292], [737, 580, 1655046422305], [737, 581, 1655046422358], [738, 582, 1655046422373], [740, 584, 1655046422385], [742, 587, 1655046422398], [743, 587, 1655046422414], [744, 589, 1655046422426], [748, 592, 1655046422438], [751, 595, 1655046422452], [755, 598, 1655046422465], [757, 599, 1655046422478], [757, 600, 1655046422492], [758, 600, 1655046422506], [759, 600, 1655046422518], [760, 600, 1655046422562], [761, 600, 1655046422577], [762, 600, 1655046422587], [763, 600, 1655046422598], [765, 600, 1655046422611], [766, 600, 1655046422625], [768, 600, 1655046422638], [769, 600, 1655046422651], [770, 600, 1655046422664], [771, 600, 1655046422678], [772, 600, 1655046422698], [773, 600, 1655046422706], [774, 600, 1655046422718], [777, 600, 1655046422732], [780, 600, 1655046422748], [781, 600, 1655046422761], [782, 600, 1655046422775], [783, 600, 1655046422825], [784, 600, 1655046422848], [785, 601, 1655046422884], [786, 601, 1655046422918], [789, 601, 1655046422932], [790, 601, 1655046422945], [793, 601, 1655046422959], [795, 601, 1655046422972], [796, 601, 1655046422985], [798, 601, 1655046422998], [799, 601, 1655046423012], [802, 601, 1655046423025], [803, 601, 1655046423039], [805, 601, 1655046423052], [807, 601, 1655046423065], [810, 601, 1655046423078], [811, 601, 1655046423092], [814, 601, 1655046423105], [815, 601, 1655046423118], [818, 601, 1655046423132], [820, 600, 1655046423145], [823, 600, 1655046423159], [826, 600, 1655046423173], [827, 600, 1655046423185], [830, 600, 1655046423198], [832, 600, 1655046423212], [834, 600, 1655046423225], [835, 600, 1655046423239], [838, 600, 1655046423252], [839, 600, 1655046423265], [844, 600, 1655046423278], [847, 600, 1655046423292], [850, 600, 1655046423305], [851, 600, 1655046423318], [856, 600, 1655046423332], [860, 600, 1655046423345], [866, 600, 1655046423359], [869, 600, 1655046423372], [872, 600, 1655046423386], [879, 600, 1655046423399], [882, 600, 1655046423412], [888, 600, 1655046423426], [892, 600, 1655046423438], [896, 600, 1655046423451], [898, 600, 1655046423464], [901, 600, 1655046423478], [906, 600, 1655046423491], [907, 600, 1655046423504], [911, 600, 1655046423518], [915, 600, 1655046423531], [917, 600, 1655046423544], [924, 600, 1655046423558], [926, 600, 1655046423571], [935, 600, 1655046423584], [937, 600, 1655046423598], [940, 600, 1655046423612], [943, 600, 1655046423625], [945, 600, 1655046423638], [947, 600, 1655046423652], [948, 600, 1655046423665], [951, 601, 1655046423679], [953, 601, 1655046423692], [956, 601, 1655046423705], [958, 601, 1655046423719], [961, 601, 1655046423732], [963, 601, 1655046423745], [966, 601, 1655046423759], [969, 602, 1655046423772], [972, 602, 1655046423785], [973, 602, 1655046423799], [974, 602, 1655046423812], [975, 602, 1655046423825], [977, 602, 1655046423839], [980, 602, 1655046423852], [981, 602, 1655046423865], [983, 602, 1655046423879], [986, 602, 1655046423892], [989, 602, 1655046423905], [993, 602, 1655046423919], [998, 602, 1655046423932], [1001, 602, 1655046423945], [1006, 602, 1655046423959], [1012, 602, 1655046423972], [1014, 602, 1655046423986], [1020, 602, 1655046423998], [1026, 602, 1655046424012], [1028, 602, 1655046424025], [1032, 602, 1655046424038], [1036, 602, 1655046424052], [1039, 602, 1655046424066], [1043, 602, 1655046424079], [1046, 602, 1655046424092], [1049, 602, 1655046424105], [1052, 602, 1655046424119], [1054, 602, 1655046424132], [1057, 602, 1655046424145], [1060, 602, 1655046424159], [1061, 602, 1655046424172], [1065, 602, 1655046424185], [1069, 602, 1655046424198], [1072, 602, 1655046424212], [1078, 602, 1655046424225], [1086, 602, 1655046424239], [1089, 602, 1655046424252], [1094, 603, 1655046424266], [1098, 603, 1655046424279], [1100, 603, 1655046424292], [1104, 603, 1655046424306], [1108, 603, 1655046424319], [1113, 603, 1655046424333], [1115, 603, 1655046424345], [1119, 603, 1655046424359], [1121, 603, 1655046424372], [1125, 603, 1655046424386], [1131, 603, 1655046424412], [1133, 603, 1655046424425], [1135, 603, 1655046424438], [1138, 603, 1655046424452], [1140, 603, 1655046424466], [1141, 603, 1655046424480], [1142, 603, 1655046424493], [1144, 603, 1655046424508], [1145, 604, 1655046424519], [1146, 604, 1655046424533], [1147, 604, 1655046424559], [1148, 604, 1655046424607], [1149, 604, 1655046424625], [1150, 604, 1655046424639], [1151, 605, 1655046424655], [1152, 605, 1655046424705], [1154, 605, 1655046424719], [1155, 605, 1655046424733], [1156, 605, 1655046424745], [1156, 605, 1655046424840], [1156, 606, 1655046424859], [1152, 606, 1655046424868], [1143, 607, 1655046424878], [1124, 613, 1655046424891], [1105, 618, 1655046424905], [1073, 627, 1655046424918], [1034, 638, 1655046424932], [1025, 641, 1655046424945], [984, 649, 1655046424958], [941, 656, 1655046424972], [902, 662, 1655046424985], [829, 670, 1655046424998], [790, 674, 1655046425012], [715, 684, 1655046425025], [655, 686, 1655046425038], [611, 689, 1655046425052], [589, 690, 1655046425065], [527, 695, 1655046425078], [506, 697, 1655046425092], [452, 700, 1655046425105], [403, 703, 1655046425119], [389, 705, 1655046425132], [355, 709, 1655046425145], [319, 711, 1655046425159], [309, 711, 1655046425172], [279, 711, 1655046425186], [260, 711, 1655046425199], [252, 711, 1655046425212], [234, 711, 1655046425225], [219, 712, 1655046425239], [212, 712, 1655046425252], [193, 712, 1655046425265], [171, 713, 1655046425279], [165, 713, 1655046425292], [153, 715, 1655046425306], [138, 716, 1655046425318], [132, 717, 1655046425333], [122, 718, 1655046425347], [114, 718, 1655046425360], [102, 718, 1655046425373], [94, 718, 1655046425387], [84, 718, 1655046425402], [71, 719, 1655046425416], [67, 719, 1655046425428], [55, 719, 1655046425441], [44, 719, 1655046425456], [35, 719, 1655046425472], [31, 719, 1655046425484], [27, 719, 1655046425495], [26, 719, 1655046425506], [25, 719, 1655046425520], [24, 719, 1655046425536]] 39 | mouse_track = MouseTrack(trace_answer_unlock) 40 | mouse_track.show_track() 41 | ``` 42 | ![](imgs/feature_engineering/trace_answer_unlock.png) 43 | 44 | ### 鼠标移动合速度 45 | ```python 46 | feature_dev_order1, feature_dev_order2 = mouse_track.get_feature_dev(order=2, mode="combine") 47 | import matplotlib.pyplot as plt 48 | plt.plot(mouse_track.arr_trace[:len(feature_dev_order1),-1], feature_dev_order1) 49 | plt.show() 50 | ``` 51 | ![](imgs/feature_engineering/feature_dev_order1.png) 52 | 53 | 从上图可以看出,第一个峰是答完题,向滑块验证码的快速移动,第二个峰是解锁滑块后,向提交按钮快速移动 54 | 55 | ### 鼠标移动合加速度 56 | ```python 57 | plt.plot(mouse_track.arr_trace[:len(feature_dev_order1),-1], feature_dev_order1) 58 | plt.xlabel("time") 59 | plt.ylabel("px/ms") 60 | plt.show() 61 | ``` 62 | ![](imgs/feature_engineering/feature_dev_order2.png) 63 | 64 | ### 鼠标移动分速度(x方向) 65 | ```python 66 | feature_dev_order1, feature_dev_order2 = mouse_track.get_feature_dev(order=2, mode="decomposition") # contants.COMBINE 67 | plt.plot(mouse_track.arr_trace[:len(feature_dev_order1), -1], feature_dev_order1[:, 0]) 68 | plt.xlabel("time") 69 | plt.ylabel("x-axis px/ms") 70 | plt.show() 71 | ``` 72 | ![](imgs/feature_engineering/feature_dev_order1_x.png) 73 | 74 | ### 鼠标移动方向角变化 75 | ```python 76 | feature_doa = mouse_track.get_feature_doa() 77 | plt.plot(mouse_track.arr_trace[:len(feature_doa), -1], feature_doa) 78 | plt.xlabel("time") 79 | plt.ylabel("angle") 80 | plt.show() 81 | ``` 82 | ![](imgs/feature_engineering/feature_doa.png) 83 | -------------------------------------------------------------------------------- /docs/source/Quick-Start.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | ## 简介 3 | 随着互联网技术的发展,鼠标轨迹识别算法在很多人机交互产品中的需求日益增加, 4 | 比如,一些网站为了防止被爬,增加了一些滑块验证码,但是一些软件已经可以模拟人的行为破解滑块验证码。 5 | 本项目就是通过对鼠标轨迹的特征分析,判定是否是人的行为还是机器行为。常见应用场景:网站反爬虫、在线考试系统脚本刷题。 6 | 7 | [Github: https://github.com/itmorn/robot-mouse-track](https://github.com/itmorn/robot-mouse-track) 8 | 9 | ## 安装 10 | `robot_mouse_track` 支持 python `3.5, 3.6, 3.7, 3.8, 3.9`. 11 | 12 | ```bash 13 | $ pip install robot_mouse_track 14 | ``` 15 | 16 | ## 简单使用robot_mouse_track 17 | 18 | 19 | ### 步骤1: 引入模型 20 | ```python 21 | from robot_mouse_track.mouse_track import MouseTrack 22 | ``` 23 | 24 | ### 步骤2: 创建鼠标轨迹对象 25 | ```python 26 | trace_itmorn = [[404, 0, 1655035839721], [409, 11, 1655035839734], [420, 29, 1655035839748], [425, 40, 1655035839761], [436, 59, 1655035839774], [443, 71, 1655035839788], [454, 90, 1655035839801], [458, 98, 1655035839814], [468, 113, 1655035839827], [474, 122, 1655035839841], [480, 131, 1655035839854], [483, 134, 1655035839868], [484, 136, 1655035839881], [484, 137, 1655035840098], [479, 139, 1655035840107], [474, 140, 1655035840121], [467, 142, 1655035840134], [450, 146, 1655035840148], [444, 147, 1655035840161], [427, 149, 1655035840174], [421, 150, 1655035840188], [420, 150, 1655035840201], [420, 151, 1655035840214], [422, 151, 1655035840254], [428, 151, 1655035840268], [440, 151, 1655035840281], [452, 151, 1655035840294], [470, 150, 1655035840308], [479, 150, 1655035840321], [492, 149, 1655035840334], [498, 149, 1655035840348], [508, 149, 1655035840361], [511, 150, 1655035840375], [513, 152, 1655035840388], [513, 153, 1655035840401], [513, 156, 1655035840414], [513, 158, 1655035840428], [513, 159, 1655035840441], [507, 166, 1655035840454], [495, 184, 1655035840468], [481, 209, 1655035840481], [463, 239, 1655035840494], [450, 258, 1655035840508], [433, 283, 1655035840521], [429, 289, 1655035840535], [417, 307, 1655035840548], [407, 324, 1655035840561], [403, 334, 1655035840574], [402, 338, 1655035840588], [402, 346, 1655035840601], [402, 349, 1655035840615], [403, 350, 1655035840628], [405, 352, 1655035840641], [412, 352, 1655035840655], [421, 349, 1655035840668], [435, 343, 1655035840681], [449, 337, 1655035840694], [461, 330, 1655035840708], [472, 326, 1655035840721], [476, 323, 1655035840735], [485, 320, 1655035840749], [490, 319, 1655035840761], [491, 319, 1655035840775], [491, 318, 1655035840824], [491, 317, 1655035840888], [492, 316, 1655035840895], [493, 313, 1655035840908], [498, 301, 1655035840921], [504, 292, 1655035840935], [515, 273, 1655035840949], [523, 260, 1655035840961], [525, 254, 1655035840975], [528, 244, 1655035840988], [529, 241, 1655035841001], [533, 226, 1655035841015], [536, 218, 1655035841028], [536, 215, 1655035841041], [537, 211, 1655035841055], [537, 208, 1655035841068], [537, 205, 1655035841081], [537, 204, 1655035841095], [536, 201, 1655035841108], [536, 200, 1655035841121], [536, 198, 1655035841135], [535, 198, 1655035841175], [537, 198, 1655035841218], [540, 198, 1655035841228], [548, 197, 1655035841242], [556, 197, 1655035841255], [575, 194, 1655035841268], [581, 194, 1655035841281], [593, 191, 1655035841295], [597, 190, 1655035841308], [601, 189, 1655035841322], [602, 189, 1655035841335], [602, 188, 1655035841375], [602, 187, 1655035841388], [602, 186, 1655035841404], [602, 185, 1655035841416], [602, 181, 1655035841429], [600, 177, 1655035841442], [596, 164, 1655035841455], [591, 144, 1655035841468], [590, 140, 1655035841482], [590, 129, 1655035841495], [590, 123, 1655035841508], [589, 117, 1655035841522], [589, 110, 1655035841535], [589, 107, 1655035841548], [589, 102, 1655035841562], [589, 98, 1655035841575], [589, 96, 1655035841588], [589, 94, 1655035841602], [589, 95, 1655035841724], [588, 98, 1655035841735], [588, 100, 1655035841749], [588, 105, 1655035841762], [587, 114, 1655035841775], [587, 115, 1655035841788], [585, 123, 1655035841802], [584, 129, 1655035841815], [583, 133, 1655035841829], [582, 140, 1655035841842], [581, 144, 1655035841855], [580, 153, 1655035841869], [579, 160, 1655035841882], [578, 170, 1655035841895], [578, 174, 1655035841908], [577, 182, 1655035841922], [576, 187, 1655035841935], [575, 196, 1655035841949], [574, 209, 1655035841962], [573, 221, 1655035841975], [573, 229, 1655035841988], [572, 243, 1655035842002], [571, 251, 1655035842016], [570, 267, 1655035842028], [570, 274, 1655035842042], [570, 279, 1655035842055], [570, 282, 1655035842068], [570, 286, 1655035842082], [570, 287, 1655035842095], [570, 291, 1655035842109], [570, 292, 1655035842122], [570, 295, 1655035842135], [570, 297, 1655035842149], [570, 299, 1655035842162], [570, 300, 1655035842175], [572, 302, 1655035842189], [573, 303, 1655035842202], [575, 304, 1655035842215], [582, 305, 1655035842229], [588, 306, 1655035842242], [592, 306, 1655035842255], [603, 306, 1655035842268], [609, 306, 1655035842282], [610, 306, 1655035842296], [611, 306, 1655035842309], [611, 305, 1655035842608], [613, 301, 1655035842616], [619, 292, 1655035842629], [622, 290, 1655035842642], [633, 278, 1655035842655], [637, 273, 1655035842669], [649, 255, 1655035842682], [664, 227, 1655035842696], [668, 217, 1655035842709], [676, 199, 1655035842722], [681, 183, 1655035842735], [682, 178, 1655035842749], [684, 174, 1655035842762], [685, 167, 1655035842775], [685, 165, 1655035842789], [685, 163, 1655035842802], [685, 160, 1655035842816], [685, 159, 1655035842829], [684, 156, 1655035842842], [683, 149, 1655035842855], [683, 147, 1655035842869], [683, 144, 1655035842882], [683, 141, 1655035842897], [683, 140, 1655035842918], [684, 139, 1655035842941], [687, 139, 1655035842963], [692, 145, 1655035842976], [694, 149, 1655035842989], [700, 163, 1655035843002], [705, 186, 1655035843016], [706, 194, 1655035843029], [706, 218, 1655035843043], [706, 227, 1655035843056], [706, 248, 1655035843069], [703, 284, 1655035843083], [700, 297, 1655035843096], [696, 316, 1655035843109], [695, 325, 1655035843122], [694, 327, 1655035843136], [694, 320, 1655035843190], [694, 306, 1655035843203], [696, 285, 1655035843216], [697, 273, 1655035843229], [699, 264, 1655035843243], [701, 237, 1655035843256], [706, 207, 1655035843274], [709, 194, 1655035843288], [711, 184, 1655035843297], [714, 172, 1655035843311], [717, 164, 1655035843322], [718, 162, 1655035843335], [719, 160, 1655035843349], [720, 159, 1655035843362], [721, 159, 1655035843375], [722, 159, 1655035843388], [724, 159, 1655035843402], [725, 159, 1655035843415], [729, 161, 1655035843429], [733, 172, 1655035843442], [735, 182, 1655035843455], [736, 197, 1655035843468], [736, 225, 1655035843482], [736, 242, 1655035843495], [736, 258, 1655035843510], [736, 266, 1655035843523], [736, 285, 1655035843536], [736, 303, 1655035843550], [736, 310, 1655035843563], [736, 315, 1655035843576], [736, 316, 1655035843589], [736, 315, 1655035843616], [736, 313, 1655035843630], [736, 298, 1655035843643], [738, 265, 1655035843656], [740, 239, 1655035843669], [742, 227, 1655035843683], [748, 205, 1655035843696], [750, 196, 1655035843709], [754, 185, 1655035843723], [755, 177, 1655035843736], [757, 167, 1655035843749], [759, 163, 1655035843763], [762, 157, 1655035843777], [764, 154, 1655035843789], [768, 151, 1655035843803], [772, 148, 1655035843817], [774, 146, 1655035843829], [775, 146, 1655035843843], [776, 146, 1655035843856], [778, 146, 1655035843869], [780, 146, 1655035843883], [781, 146, 1655035843896], [785, 147, 1655035843910], [788, 149, 1655035843923], [792, 154, 1655035843936], [797, 159, 1655035843949], [800, 163, 1655035843963], [801, 165, 1655035843976], [805, 170, 1655035843990], [807, 174, 1655035844003], [808, 179, 1655035844016], [809, 190, 1655035844029], [810, 194, 1655035844043], [810, 198, 1655035844056], [810, 207, 1655035844070], [811, 217, 1655035844083], [811, 226, 1655035844096], [811, 234, 1655035844109], [811, 239, 1655035844123], [810, 247, 1655035844136], [809, 253, 1655035844150], [809, 262, 1655035844163], [807, 270, 1655035844178], [807, 274, 1655035844190], [807, 281, 1655035844205], [807, 289, 1655035844218], [807, 292, 1655035844230], [807, 295, 1655035844243], [808, 299, 1655035844256], [808, 300, 1655035844270], [808, 299, 1655035844369], [807, 295, 1655035844390], [806, 294, 1655035844404], [812, 289, 1655035844750], [820, 284, 1655035844763], [820, 283, 1655035844777], [821, 283, 1655035844790], [822, 283, 1655035844803], [824, 283, 1655035844818], [824, 284, 1655035844857], [829, 286, 1655035844871], [835, 289, 1655035844883], [847, 289, 1655035844898], [866, 288, 1655035844910], [878, 285, 1655035844923], [897, 276, 1655035844937], [910, 264, 1655035844950], [921, 248, 1655035844963], [927, 238, 1655035844976], [941, 206, 1655035844990], [946, 193, 1655035845003], [949, 185, 1655035845017], [953, 171, 1655035845031], [955, 158, 1655035845043], [955, 148, 1655035845057], [955, 143, 1655035845070], [954, 142, 1655035845083], [951, 141, 1655035845098], [946, 140, 1655035845110], [943, 140, 1655035845124], [938, 140, 1655035845137], [929, 146, 1655035845150], [924, 150, 1655035845163], [920, 157, 1655035845177], [916, 171, 1655035845190], [915, 182, 1655035845204], [915, 212, 1655035845217], [915, 222, 1655035845231], [916, 244, 1655035845245], [919, 263, 1655035845257], [924, 275, 1655035845270], [927, 279, 1655035845283], [930, 282, 1655035845298], [940, 285, 1655035845312], [951, 285, 1655035845323], [963, 283, 1655035845337], [969, 280, 1655035845351], [983, 271, 1655035845364], [993, 263, 1655035845377], [999, 257, 1655035845390], [1005, 247, 1655035845403], [1012, 228, 1655035845417], [1012, 222, 1655035845431], [1014, 200, 1655035845445], [1014, 181, 1655035845462], [1014, 167, 1655035845472], [1013, 161, 1655035845484], [1011, 156, 1655035845498], [1008, 150, 1655035845511], [1003, 145, 1655035845524], [999, 143, 1655035845537], [994, 143, 1655035845550], [987, 142, 1655035845564], [982, 141, 1655035845578], [965, 140, 1655035845590], [953, 140, 1655035845604], [947, 140, 1655035845620], [941, 140, 1655035845632], [939, 140, 1655035845647], [937, 141, 1655035845658], [936, 143, 1655035845688], [936, 144, 1655035845709], [936, 145, 1655035845917], [940, 147, 1655035845989], [949, 150, 1655035846007], [952, 150, 1655035846018], [968, 155, 1655035846030], [978, 158, 1655035846046], [985, 159, 1655035846058], [996, 160, 1655035846070], [1014, 162, 1655035846084], [1021, 162, 1655035846097], [1033, 162, 1655035846112], [1042, 162, 1655035846124], [1059, 162, 1655035846137], [1069, 162, 1655035846151], [1083, 159, 1655035846164], [1086, 157, 1655035846178], [1088, 156, 1655035846191], [1089, 154, 1655035846204], [1090, 151, 1655035846217], [1090, 150, 1655035846232], [1090, 147, 1655035846245], [1090, 145, 1655035846257], [1090, 142, 1655035846271], [1087, 140, 1655035846310], [1086, 139, 1655035846322], [1087, 139, 1655035846383], [1088, 141, 1655035846393], [1089, 146, 1655035846405], [1092, 157, 1655035846418], [1093, 165, 1655035846432], [1095, 185, 1655035846445], [1099, 204, 1655035846457], [1100, 213, 1655035846471], [1103, 238, 1655035846484], [1103, 246, 1655035846498], [1103, 272, 1655035846511], [1103, 290, 1655035846525], [1103, 294, 1655035846538], [1103, 291, 1655035846591], [1103, 284, 1655035846604], [1103, 279, 1655035846618], [1103, 274, 1655035846632], [1105, 254, 1655035846647], [1110, 221, 1655035846664], [1116, 190, 1655035846681], [1119, 174, 1655035846696], [1124, 163, 1655035846716], [1129, 155, 1655035846730], [1134, 151, 1655035846744], [1141, 149, 1655035846757], [1153, 149, 1655035846770], [1169, 149, 1655035846790], [1182, 150, 1655035846807], [1192, 151, 1655035846819], [1196, 152, 1655035846830], [1198, 153, 1655035846843], [1199, 153, 1655035847148], [1207, 152, 1655035847164], [1210, 152, 1655035847179], [1218, 151, 1655035847193], [1223, 150, 1655035847205], [1231, 146, 1655035847218], [1233, 145, 1655035847231], [1235, 142, 1655035847245], [1235, 141, 1655035847258], [1235, 137, 1655035847271], [1235, 136, 1655035847284], [1235, 134, 1655035847299], [1235, 132, 1655035847313], [1235, 131, 1655035847324], [1235, 130, 1655035847351], [1235, 129, 1655035847365], [1237, 129, 1655035847398], [1238, 130, 1655035847410], [1241, 134, 1655035847423], [1244, 139, 1655035847436], [1251, 150, 1655035847450], [1258, 159, 1655035847462], [1261, 163, 1655035847474], [1266, 170, 1655035847487], [1272, 185, 1655035847501], [1277, 214, 1655035847514], [1277, 226, 1655035847527], [1277, 246, 1655035847539], [1274, 256, 1655035847551], [1268, 271, 1655035847565], [1260, 282, 1655035847579], [1256, 287, 1655035847593], [1254, 288, 1655035847606], [1254, 287, 1655035847641], [1254, 279, 1655035847654], [1254, 265, 1655035847666], [1256, 252, 1655035847681], [1259, 236, 1655035847694], [1263, 219, 1655035847712], [1270, 201, 1655035847725], [1274, 191, 1655035847738], [1278, 178, 1655035847755], [1280, 172, 1655035847769], [1283, 163, 1655035847783], [1284, 158, 1655035847797], [1285, 157, 1655035847810], [1285, 156, 1655035847823], [1286, 154, 1655035847836], [1287, 153, 1655035847850], [1287, 152, 1655035847871], [1288, 152, 1655035847886], [1289, 151, 1655035847899], [1290, 151, 1655035847917], [1291, 151, 1655035847930], [1292, 151, 1655035847952], [1296, 151, 1655035847968], [1301, 155, 1655035847982], [1304, 156, 1655035847996], [1309, 159, 1655035848008], [1312, 160, 1655035848022], [1314, 162, 1655035848038], [1315, 167, 1655035848052], [1316, 171, 1655035848066], [1317, 180, 1655035848080], [1318, 192, 1655035848095], [1319, 201, 1655035848110], [1319, 209, 1655035848125], [1320, 215, 1655035848138], [1321, 225, 1655035848152], [1321, 241, 1655035848178], [1321, 249, 1655035848192], [1320, 259, 1655035848205], [1320, 262, 1655035848218], [1320, 269, 1655035848232], [1320, 275, 1655035848249], [1321, 281, 1655035848264], [1323, 285, 1655035848279], [1324, 286, 1655035848292], [1327, 288, 1655035848306], [1336, 291, 1655035848321], [1347, 292, 1655035848338], [1358, 292, 1655035848352], [1366, 291, 1655035848366], [1371, 289, 1655035848379], [1376, 286, 1655035848393], [1377, 285, 1655035848409], [1378, 285, 1655035848729], [1379, 285, 1655035848752], [1380, 285, 1655035848767], [1381, 285, 1655035848782], [1378, 286, 1655035848955], [1359, 297, 1655035848970], [1337, 307, 1655035848983], [1291, 324, 1655035848996], [1231, 347, 1655035849011], [1198, 360, 1655035849026], [1091, 408, 1655035849041], [969, 450, 1655035849055], [830, 488, 1655035849068], [696, 518, 1655035849084], [601, 539, 1655035849100], [545, 551, 1655035849115], [468, 567, 1655035849129], [408, 581, 1655035849143], [363, 592, 1655035849159], [336, 601, 1655035849179], [329, 604, 1655035849193], [319, 613, 1655035849209], [304, 630, 1655035849231], [293, 639, 1655035849246], [283, 646, 1655035849260], [265, 655, 1655035849274], [238, 669, 1655035849290], [223, 676, 1655035849306], [205, 683, 1655035849321], [194, 688, 1655035849336], [185, 693, 1655035849352], [168, 698, 1655035849372], [162, 699, 1655035849386], [153, 700, 1655035849400], [140, 701, 1655035849411], [122, 703, 1655035849421], [112, 704, 1655035849431], [106, 704, 1655035849445], [93, 706, 1655035849459], [81, 706, 1655035849475], [69, 709, 1655035849493], [58, 710, 1655035849509], [47, 710, 1655035849525], [43, 710, 1655035849542], [39, 710, 1655035849559], [38, 710, 1655035849573], [37, 710, 1655035849588], [36, 710, 1655035849606], [35, 711, 1655035849621], [32, 714, 1655035849639], [27, 717, 1655035849654], [23, 719, 1655035849669], [21, 721, 1655035849683], [21, 723, 1655035849700]] 27 | mouse_track = MouseTrack(trace_itmorn) 28 | ``` 29 | trace_example,表示鼠标轨迹的序列;其中,每一项为`[坐标x,坐标y,时间戳t]` 30 | 31 | ### 步骤3: 可视化观察轨迹 32 | ```python 33 | mouse_track.show_track() 34 | ``` 35 | ![](imgs/quick_start/trace_itmorn.png) 36 | 37 | 其对应的收集客户端为浏览器,下图展示了用户鼠标浏览器上移动的轨迹 38 | ![](imgs/quick_start/trace_itmorn_browser.png) 39 | 如果你想为自己的客户端添加收集鼠标轨迹的JavaScript代码, 40 | 可以参考[鼠标轨迹数据的收集](Collect-Data.md) 41 | 42 | 43 | ### 步骤4: 添加要检测的机器行为类型 44 | 这里我们以检测鼠标移动速度和加速度过大(直观感觉就是鼠标在跳动)为例 45 | ```python 46 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 47 | ``` 48 | 其中,th_velocity为速度阈值(单位是px/ms),经过评测,一般用户移动鼠标的速度不会超过该值; 49 | th_accelerationth_velocity为加速度阈值,经过评测,一般用户移动鼠标的加速度不会超过该值 50 | 更多的机器行为可以参考 [机器行为类](risk_motion/index) 51 | 52 | ### 步骤5: 计算风险值 53 | ```python 54 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 55 | >>> False 0.5542333048572756 0.25969806234590154 56 | ``` 57 | flag表示是否触发风险;exceed_times_velocity 表示速度触发风险等级,越高表示风险越高; 58 | exceed_times_acceleration 表示加速度触发风险等级,越高表示风险越高 59 | 60 | 用户可以根据这两个风险等级,根据自身业务需求,调整计算风险的权重。 61 | 62 | trace_itmorn是一段真实的鼠标轨迹;下面我们使用selenium操作浏览器,产生一段机器轨迹, 63 | 观察程序的识别效果 产生该轨迹的脚本为: 64 | [use_selenium_jump.py](https://github.com/itmorn/robot-mouse-track/blob/main/examples/use_selenium_jump.py) 65 | 66 | 在浏览器上留下的轨迹只能看到一点点 67 | 68 | ![](imgs/quick_start/selenium_jump_browser.png) 69 | 70 | 后端程序收集到轨迹为 71 | 72 | ![](imgs/quick_start/selenium_jump.png) 73 | 74 | 接着,使用程序对该轨迹进行判定: 75 | ```python 76 | trace_selenium_jump = [[6, 83, 1655038106398], [6, 240, 1655038107474], [6, 376, 1655038108650], [285, 601, 1655038109698], [305, 601, 1655038110224], [325, 601, 1655038110738], [345, 601, 1655038111263], [365, 601, 1655038111782], [385, 601, 1655038112307], [405, 601, 1655038112831], [425, 601, 1655038113342], [445, 601, 1655038113884], [465, 601, 1655038114396], [485, 601, 1655038114921], [505, 601, 1655038115453], [525, 601, 1655038115973], [545, 601, 1655038116500], [565, 601, 1655038117035], [585, 601, 1655038117566], [605, 601, 1655038118095], [625, 601, 1655038118635], [645, 601, 1655038119177], [15, 721, 1655038120794]] 77 | mouse_track = MouseTrack(trace_selenium_jump) 78 | mouse_track.show_track() 79 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 80 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 81 | print(flag,exceed_times_velocity,exceed_times_acceleration) 82 | >>> True 1.603316874482396 1.1095120532017115 83 | ``` 84 | 可以看出,flag表明触发了风险,速度和加速度权值也都大于1.0。 85 | 86 | -------------------------------------------------------------------------------- /docs/source/Rule-Setting.md: -------------------------------------------------------------------------------- 1 | # 设置规则 2 | 3 | 新建鼠标轨迹对象: 4 | ```python 5 | trace_itmorn = [[404, 0, 1655035839721], [409, 11, 1655035839734], [420, 29, 1655035839748], [425, 40, 1655035839761], [436, 59, 1655035839774], [443, 71, 1655035839788], [454, 90, 1655035839801], [458, 98, 1655035839814], [468, 113, 1655035839827], [474, 122, 1655035839841], [480, 131, 1655035839854], [483, 134, 1655035839868], [484, 136, 1655035839881], [484, 137, 1655035840098], [479, 139, 1655035840107], [474, 140, 1655035840121], [467, 142, 1655035840134], [450, 146, 1655035840148], [444, 147, 1655035840161], [427, 149, 1655035840174], [421, 150, 1655035840188], [420, 150, 1655035840201], [420, 151, 1655035840214], [422, 151, 1655035840254], [428, 151, 1655035840268], [440, 151, 1655035840281], [452, 151, 1655035840294], [470, 150, 1655035840308], [479, 150, 1655035840321], [492, 149, 1655035840334], [498, 149, 1655035840348], [508, 149, 1655035840361], [511, 150, 1655035840375], [513, 152, 1655035840388], [513, 153, 1655035840401], [513, 156, 1655035840414], [513, 158, 1655035840428], [513, 159, 1655035840441], [507, 166, 1655035840454], [495, 184, 1655035840468], [481, 209, 1655035840481], [463, 239, 1655035840494], [450, 258, 1655035840508], [433, 283, 1655035840521], [429, 289, 1655035840535], [417, 307, 1655035840548], [407, 324, 1655035840561], [403, 334, 1655035840574], [402, 338, 1655035840588], [402, 346, 1655035840601], [402, 349, 1655035840615], [403, 350, 1655035840628], [405, 352, 1655035840641], [412, 352, 1655035840655], [421, 349, 1655035840668], [435, 343, 1655035840681], [449, 337, 1655035840694], [461, 330, 1655035840708], [472, 326, 1655035840721], [476, 323, 1655035840735], [485, 320, 1655035840749], [490, 319, 1655035840761], [491, 319, 1655035840775], [491, 318, 1655035840824], [491, 317, 1655035840888], [492, 316, 1655035840895], [493, 313, 1655035840908], [498, 301, 1655035840921], [504, 292, 1655035840935], [515, 273, 1655035840949], [523, 260, 1655035840961], [525, 254, 1655035840975], [528, 244, 1655035840988], [529, 241, 1655035841001], [533, 226, 1655035841015], [536, 218, 1655035841028], [536, 215, 1655035841041], [537, 211, 1655035841055], [537, 208, 1655035841068], [537, 205, 1655035841081], [537, 204, 1655035841095], [536, 201, 1655035841108], [536, 200, 1655035841121], [536, 198, 1655035841135], [535, 198, 1655035841175], [537, 198, 1655035841218], [540, 198, 1655035841228], [548, 197, 1655035841242], [556, 197, 1655035841255], [575, 194, 1655035841268], [581, 194, 1655035841281], [593, 191, 1655035841295], [597, 190, 1655035841308], [601, 189, 1655035841322], [602, 189, 1655035841335], [602, 188, 1655035841375], [602, 187, 1655035841388], [602, 186, 1655035841404], [602, 185, 1655035841416], [602, 181, 1655035841429], [600, 177, 1655035841442], [596, 164, 1655035841455], [591, 144, 1655035841468], [590, 140, 1655035841482], [590, 129, 1655035841495], [590, 123, 1655035841508], [589, 117, 1655035841522], [589, 110, 1655035841535], [589, 107, 1655035841548], [589, 102, 1655035841562], [589, 98, 1655035841575], [589, 96, 1655035841588], [589, 94, 1655035841602], [589, 95, 1655035841724], [588, 98, 1655035841735], [588, 100, 1655035841749], [588, 105, 1655035841762], [587, 114, 1655035841775], [587, 115, 1655035841788], [585, 123, 1655035841802], [584, 129, 1655035841815], [583, 133, 1655035841829], [582, 140, 1655035841842], [581, 144, 1655035841855], [580, 153, 1655035841869], [579, 160, 1655035841882], [578, 170, 1655035841895], [578, 174, 1655035841908], [577, 182, 1655035841922], [576, 187, 1655035841935], [575, 196, 1655035841949], [574, 209, 1655035841962], [573, 221, 1655035841975], [573, 229, 1655035841988], [572, 243, 1655035842002], [571, 251, 1655035842016], [570, 267, 1655035842028], [570, 274, 1655035842042], [570, 279, 1655035842055], [570, 282, 1655035842068], [570, 286, 1655035842082], [570, 287, 1655035842095], [570, 291, 1655035842109], [570, 292, 1655035842122], [570, 295, 1655035842135], [570, 297, 1655035842149], [570, 299, 1655035842162], [570, 300, 1655035842175], [572, 302, 1655035842189], [573, 303, 1655035842202], [575, 304, 1655035842215], [582, 305, 1655035842229], [588, 306, 1655035842242], [592, 306, 1655035842255], [603, 306, 1655035842268], [609, 306, 1655035842282], [610, 306, 1655035842296], [611, 306, 1655035842309], [611, 305, 1655035842608], [613, 301, 1655035842616], [619, 292, 1655035842629], [622, 290, 1655035842642], [633, 278, 1655035842655], [637, 273, 1655035842669], [649, 255, 1655035842682], [664, 227, 1655035842696], [668, 217, 1655035842709], [676, 199, 1655035842722], [681, 183, 1655035842735], [682, 178, 1655035842749], [684, 174, 1655035842762], [685, 167, 1655035842775], [685, 165, 1655035842789], [685, 163, 1655035842802], [685, 160, 1655035842816], [685, 159, 1655035842829], [684, 156, 1655035842842], [683, 149, 1655035842855], [683, 147, 1655035842869], [683, 144, 1655035842882], [683, 141, 1655035842897], [683, 140, 1655035842918], [684, 139, 1655035842941], [687, 139, 1655035842963], [692, 145, 1655035842976], [694, 149, 1655035842989], [700, 163, 1655035843002], [705, 186, 1655035843016], [706, 194, 1655035843029], [706, 218, 1655035843043], [706, 227, 1655035843056], [706, 248, 1655035843069], [703, 284, 1655035843083], [700, 297, 1655035843096], [696, 316, 1655035843109], [695, 325, 1655035843122], [694, 327, 1655035843136], [694, 320, 1655035843190], [694, 306, 1655035843203], [696, 285, 1655035843216], [697, 273, 1655035843229], [699, 264, 1655035843243], [701, 237, 1655035843256], [706, 207, 1655035843274], [709, 194, 1655035843288], [711, 184, 1655035843297], [714, 172, 1655035843311], [717, 164, 1655035843322], [718, 162, 1655035843335], [719, 160, 1655035843349], [720, 159, 1655035843362], [721, 159, 1655035843375], [722, 159, 1655035843388], [724, 159, 1655035843402], [725, 159, 1655035843415], [729, 161, 1655035843429], [733, 172, 1655035843442], [735, 182, 1655035843455], [736, 197, 1655035843468], [736, 225, 1655035843482], [736, 242, 1655035843495], [736, 258, 1655035843510], [736, 266, 1655035843523], [736, 285, 1655035843536], [736, 303, 1655035843550], [736, 310, 1655035843563], [736, 315, 1655035843576], [736, 316, 1655035843589], [736, 315, 1655035843616], [736, 313, 1655035843630], [736, 298, 1655035843643], [738, 265, 1655035843656], [740, 239, 1655035843669], [742, 227, 1655035843683], [748, 205, 1655035843696], [750, 196, 1655035843709], [754, 185, 1655035843723], [755, 177, 1655035843736], [757, 167, 1655035843749], [759, 163, 1655035843763], [762, 157, 1655035843777], [764, 154, 1655035843789], [768, 151, 1655035843803], [772, 148, 1655035843817], [774, 146, 1655035843829], [775, 146, 1655035843843], [776, 146, 1655035843856], [778, 146, 1655035843869], [780, 146, 1655035843883], [781, 146, 1655035843896], [785, 147, 1655035843910], [788, 149, 1655035843923], [792, 154, 1655035843936], [797, 159, 1655035843949], [800, 163, 1655035843963], [801, 165, 1655035843976], [805, 170, 1655035843990], [807, 174, 1655035844003], [808, 179, 1655035844016], [809, 190, 1655035844029], [810, 194, 1655035844043], [810, 198, 1655035844056], [810, 207, 1655035844070], [811, 217, 1655035844083], [811, 226, 1655035844096], [811, 234, 1655035844109], [811, 239, 1655035844123], [810, 247, 1655035844136], [809, 253, 1655035844150], [809, 262, 1655035844163], [807, 270, 1655035844178], [807, 274, 1655035844190], [807, 281, 1655035844205], [807, 289, 1655035844218], [807, 292, 1655035844230], [807, 295, 1655035844243], [808, 299, 1655035844256], [808, 300, 1655035844270], [808, 299, 1655035844369], [807, 295, 1655035844390], [806, 294, 1655035844404], [812, 289, 1655035844750], [820, 284, 1655035844763], [820, 283, 1655035844777], [821, 283, 1655035844790], [822, 283, 1655035844803], [824, 283, 1655035844818], [824, 284, 1655035844857], [829, 286, 1655035844871], [835, 289, 1655035844883], [847, 289, 1655035844898], [866, 288, 1655035844910], [878, 285, 1655035844923], [897, 276, 1655035844937], [910, 264, 1655035844950], [921, 248, 1655035844963], [927, 238, 1655035844976], [941, 206, 1655035844990], [946, 193, 1655035845003], [949, 185, 1655035845017], [953, 171, 1655035845031], [955, 158, 1655035845043], [955, 148, 1655035845057], [955, 143, 1655035845070], [954, 142, 1655035845083], [951, 141, 1655035845098], [946, 140, 1655035845110], [943, 140, 1655035845124], [938, 140, 1655035845137], [929, 146, 1655035845150], [924, 150, 1655035845163], [920, 157, 1655035845177], [916, 171, 1655035845190], [915, 182, 1655035845204], [915, 212, 1655035845217], [915, 222, 1655035845231], [916, 244, 1655035845245], [919, 263, 1655035845257], [924, 275, 1655035845270], [927, 279, 1655035845283], [930, 282, 1655035845298], [940, 285, 1655035845312], [951, 285, 1655035845323], [963, 283, 1655035845337], [969, 280, 1655035845351], [983, 271, 1655035845364], [993, 263, 1655035845377], [999, 257, 1655035845390], [1005, 247, 1655035845403], [1012, 228, 1655035845417], [1012, 222, 1655035845431], [1014, 200, 1655035845445], [1014, 181, 1655035845462], [1014, 167, 1655035845472], [1013, 161, 1655035845484], [1011, 156, 1655035845498], [1008, 150, 1655035845511], [1003, 145, 1655035845524], [999, 143, 1655035845537], [994, 143, 1655035845550], [987, 142, 1655035845564], [982, 141, 1655035845578], [965, 140, 1655035845590], [953, 140, 1655035845604], [947, 140, 1655035845620], [941, 140, 1655035845632], [939, 140, 1655035845647], [937, 141, 1655035845658], [936, 143, 1655035845688], [936, 144, 1655035845709], [936, 145, 1655035845917], [940, 147, 1655035845989], [949, 150, 1655035846007], [952, 150, 1655035846018], [968, 155, 1655035846030], [978, 158, 1655035846046], [985, 159, 1655035846058], [996, 160, 1655035846070], [1014, 162, 1655035846084], [1021, 162, 1655035846097], [1033, 162, 1655035846112], [1042, 162, 1655035846124], [1059, 162, 1655035846137], [1069, 162, 1655035846151], [1083, 159, 1655035846164], [1086, 157, 1655035846178], [1088, 156, 1655035846191], [1089, 154, 1655035846204], [1090, 151, 1655035846217], [1090, 150, 1655035846232], [1090, 147, 1655035846245], [1090, 145, 1655035846257], [1090, 142, 1655035846271], [1087, 140, 1655035846310], [1086, 139, 1655035846322], [1087, 139, 1655035846383], [1088, 141, 1655035846393], [1089, 146, 1655035846405], [1092, 157, 1655035846418], [1093, 165, 1655035846432], [1095, 185, 1655035846445], [1099, 204, 1655035846457], [1100, 213, 1655035846471], [1103, 238, 1655035846484], [1103, 246, 1655035846498], [1103, 272, 1655035846511], [1103, 290, 1655035846525], [1103, 294, 1655035846538], [1103, 291, 1655035846591], [1103, 284, 1655035846604], [1103, 279, 1655035846618], [1103, 274, 1655035846632], [1105, 254, 1655035846647], [1110, 221, 1655035846664], [1116, 190, 1655035846681], [1119, 174, 1655035846696], [1124, 163, 1655035846716], [1129, 155, 1655035846730], [1134, 151, 1655035846744], [1141, 149, 1655035846757], [1153, 149, 1655035846770], [1169, 149, 1655035846790], [1182, 150, 1655035846807], [1192, 151, 1655035846819], [1196, 152, 1655035846830], [1198, 153, 1655035846843], [1199, 153, 1655035847148], [1207, 152, 1655035847164], [1210, 152, 1655035847179], [1218, 151, 1655035847193], [1223, 150, 1655035847205], [1231, 146, 1655035847218], [1233, 145, 1655035847231], [1235, 142, 1655035847245], [1235, 141, 1655035847258], [1235, 137, 1655035847271], [1235, 136, 1655035847284], [1235, 134, 1655035847299], [1235, 132, 1655035847313], [1235, 131, 1655035847324], [1235, 130, 1655035847351], [1235, 129, 1655035847365], [1237, 129, 1655035847398], [1238, 130, 1655035847410], [1241, 134, 1655035847423], [1244, 139, 1655035847436], [1251, 150, 1655035847450], [1258, 159, 1655035847462], [1261, 163, 1655035847474], [1266, 170, 1655035847487], [1272, 185, 1655035847501], [1277, 214, 1655035847514], [1277, 226, 1655035847527], [1277, 246, 1655035847539], [1274, 256, 1655035847551], [1268, 271, 1655035847565], [1260, 282, 1655035847579], [1256, 287, 1655035847593], [1254, 288, 1655035847606], [1254, 287, 1655035847641], [1254, 279, 1655035847654], [1254, 265, 1655035847666], [1256, 252, 1655035847681], [1259, 236, 1655035847694], [1263, 219, 1655035847712], [1270, 201, 1655035847725], [1274, 191, 1655035847738], [1278, 178, 1655035847755], [1280, 172, 1655035847769], [1283, 163, 1655035847783], [1284, 158, 1655035847797], [1285, 157, 1655035847810], [1285, 156, 1655035847823], [1286, 154, 1655035847836], [1287, 153, 1655035847850], [1287, 152, 1655035847871], [1288, 152, 1655035847886], [1289, 151, 1655035847899], [1290, 151, 1655035847917], [1291, 151, 1655035847930], [1292, 151, 1655035847952], [1296, 151, 1655035847968], [1301, 155, 1655035847982], [1304, 156, 1655035847996], [1309, 159, 1655035848008], [1312, 160, 1655035848022], [1314, 162, 1655035848038], [1315, 167, 1655035848052], [1316, 171, 1655035848066], [1317, 180, 1655035848080], [1318, 192, 1655035848095], [1319, 201, 1655035848110], [1319, 209, 1655035848125], [1320, 215, 1655035848138], [1321, 225, 1655035848152], [1321, 241, 1655035848178], [1321, 249, 1655035848192], [1320, 259, 1655035848205], [1320, 262, 1655035848218], [1320, 269, 1655035848232], [1320, 275, 1655035848249], [1321, 281, 1655035848264], [1323, 285, 1655035848279], [1324, 286, 1655035848292], [1327, 288, 1655035848306], [1336, 291, 1655035848321], [1347, 292, 1655035848338], [1358, 292, 1655035848352], [1366, 291, 1655035848366], [1371, 289, 1655035848379], [1376, 286, 1655035848393], [1377, 285, 1655035848409], [1378, 285, 1655035848729], [1379, 285, 1655035848752], [1380, 285, 1655035848767], [1381, 285, 1655035848782], [1378, 286, 1655035848955], [1359, 297, 1655035848970], [1337, 307, 1655035848983], [1291, 324, 1655035848996], [1231, 347, 1655035849011], [1198, 360, 1655035849026], [1091, 408, 1655035849041], [969, 450, 1655035849055], [830, 488, 1655035849068], [696, 518, 1655035849084], [601, 539, 1655035849100], [545, 551, 1655035849115], [468, 567, 1655035849129], [408, 581, 1655035849143], [363, 592, 1655035849159], [336, 601, 1655035849179], [329, 604, 1655035849193], [319, 613, 1655035849209], [304, 630, 1655035849231], [293, 639, 1655035849246], [283, 646, 1655035849260], [265, 655, 1655035849274], [238, 669, 1655035849290], [223, 676, 1655035849306], [205, 683, 1655035849321], [194, 688, 1655035849336], [185, 693, 1655035849352], [168, 698, 1655035849372], [162, 699, 1655035849386], [153, 700, 1655035849400], [140, 701, 1655035849411], [122, 703, 1655035849421], [112, 704, 1655035849431], [106, 704, 1655035849445], [93, 706, 1655035849459], [81, 706, 1655035849475], [69, 709, 1655035849493], [58, 710, 1655035849509], [47, 710, 1655035849525], [43, 710, 1655035849542], [39, 710, 1655035849559], [38, 710, 1655035849573], [37, 710, 1655035849588], [36, 710, 1655035849606], [35, 711, 1655035849621], [32, 714, 1655035849639], [27, 717, 1655035849654], [23, 719, 1655035849669], [21, 721, 1655035849683], [21, 723, 1655035849700]] 6 | mouse_track = MouseTrack(trace_itmorn) 7 | mouse_track.show_track() 8 | ``` 9 | 10 | ## 跳跃检测: 11 | ```python 12 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 13 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 14 | print(flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration) 15 | >>> False JumpMotion 0.5542333048572756 0.25969806234590154 16 | ``` 17 | 18 | ## 水平/垂直移动检测: 19 | ```python 20 | rule_mouse_jump = VerticalHorizontalLinearMotion() 21 | flag, (exceed_times_x, exceed_times_y) = rule_mouse_jump.judge_risk(mouse_track) 22 | print(flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y) 23 | >>> False VerticalHorizontalLinearMotion 0.0 0.238 24 | ``` 25 | 26 | ## 斜线移动检测: 27 | ```python 28 | rule_mouse_jump = LinearMotion() 29 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 30 | print(flag, "LinearMotion", exceed_times) 31 | >>> False LinearMotion 0.0 32 | ``` 33 | 34 | ## 恒定速率/加速度移动检测: 35 | ```python 36 | rule_mouse_jump = ConstantVelocityMotion() 37 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 38 | print(flag, "ConstantVelocityMotion", exceed_times) 39 | >>> False ConstantVelocityMotion 1e-08 40 | ``` 41 | 42 | ## 缓慢移动检测: 43 | ```python 44 | rule_mouse = SlowMotion() 45 | flag, exceed_times = rule_mouse.judge_risk(mouse_track) 46 | print(flag, "SlowMotion", exceed_times) 47 | >>> False SlowMotion 0.27155963302752295 48 | ``` 49 | 50 | ## 相似轨迹检测: 51 | ```python 52 | lst_vec_bank = [] 53 | mouse_track1 = MouseTrack(trace_itmorn) 54 | vec1 = calc_vec(mouse_track1) 55 | lst_vec_bank.append(vec1) 56 | 57 | mouse_track2 = MouseTrack(trace_answer_unlock) 58 | vec_now = calc_vec(mouse_track2) 59 | 60 | rule_mouse = SimilarMotion() 61 | flag, exceed_times = rule_mouse.judge_risk(vec=vec_now, lst_vec_bank=lst_vec_bank) 62 | print(flag, "SimilarMotion", exceed_times) 63 | >>> False SimilarMotion 0.07891521311071131 64 | ``` -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../../')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'robot_mouse_track' 21 | copyright = '2022, itmorn' 22 | author = 'itmorn' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '0.0.1' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.autodoc','recommonmark','sphinx_markdown_tables' 35 | ] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The language for content autogenerated by Sphinx. Refer to documentation 41 | # for a list of supported languages. 42 | # 43 | # This is also used if you do content translation via gettext catalogs. 44 | # Usually you set "language" from the command line for these cases. 45 | language = 'zh-cn' 46 | 47 | # List of patterns, relative to source directory, that match files and 48 | # directories to ignore when looking for source files. 49 | # This pattern also affects html_static_path and html_extra_path. 50 | exclude_patterns = [] 51 | 52 | 53 | # -- Options for HTML output ------------------------------------------------- 54 | 55 | # The theme to use for HTML and HTML Help pages. See the documentation for 56 | # a list of builtin themes. 57 | # 58 | html_theme = 'alabaster' 59 | html_theme = 'sphinx_rtd_theme' 60 | 61 | # Add any paths that contain custom static files (such as style sheets) here, 62 | # relative to this directory. They are copied after the builtin static files, 63 | # so a file named "default.css" will overwrite the builtin "default.css". 64 | html_static_path = ['_static'] -------------------------------------------------------------------------------- /docs/source/imgs/algorithm/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/algorithm/01.png -------------------------------------------------------------------------------- /docs/source/imgs/algorithm/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/algorithm/02.png -------------------------------------------------------------------------------- /docs/source/imgs/feature_engineering/feature_dev_order1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/feature_engineering/feature_dev_order1.png -------------------------------------------------------------------------------- /docs/source/imgs/feature_engineering/feature_dev_order1_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/feature_engineering/feature_dev_order1_x.png -------------------------------------------------------------------------------- /docs/source/imgs/feature_engineering/feature_dev_order2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/feature_engineering/feature_dev_order2.png -------------------------------------------------------------------------------- /docs/source/imgs/feature_engineering/feature_doa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/feature_engineering/feature_doa.png -------------------------------------------------------------------------------- /docs/source/imgs/feature_engineering/trace_answer_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/feature_engineering/trace_answer_unlock.png -------------------------------------------------------------------------------- /docs/source/imgs/quick_start/selenium_jump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/quick_start/selenium_jump.png -------------------------------------------------------------------------------- /docs/source/imgs/quick_start/selenium_jump_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/quick_start/selenium_jump_browser.png -------------------------------------------------------------------------------- /docs/source/imgs/quick_start/trace_itmorn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/quick_start/trace_itmorn.png -------------------------------------------------------------------------------- /docs/source/imgs/quick_start/trace_itmorn_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/docs/source/imgs/quick_start/trace_itmorn_browser.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to robot_mouse_track's documentation! 2 | ============================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Home: 7 | 8 | 快速开始 9 | 鼠标轨迹数据的收集 10 | 特征工程 11 | 设置规则 12 | 算法原理 13 | 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | :caption: API: 18 | 19 | mouse_track/index 20 | risk_motion/index 21 | 22 | 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | -------------------------------------------------------------------------------- /docs/source/mouse_track/index.rst: -------------------------------------------------------------------------------- 1 | 鼠标轨迹类 2 | ------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | :caption: 目录: 7 | 8 | mouse_track 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/source/mouse_track/mouse_track.rst: -------------------------------------------------------------------------------- 1 | mouse_track 2 | ============ 3 | 4 | .. automodule:: robot_mouse_track.mouse_track 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/source/risk_motion/index.rst: -------------------------------------------------------------------------------- 1 | 机器行为类 2 | ------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | :caption: 目录: 7 | 8 | motion_jump 9 | motion_vertical_horizontal_linear 10 | motion_linear 11 | motion_constant_velocity 12 | motion_slow 13 | motion_similar 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_constant_velocity.rst: -------------------------------------------------------------------------------- 1 | motion_constant_velocity 2 | ======================== 3 | 4 | 5 | .. automodule:: robot_mouse_track.risk_motion.motion_constant_velocity 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_jump.rst: -------------------------------------------------------------------------------- 1 | motion_jump 2 | ================= 3 | 4 | 5 | .. automodule:: robot_mouse_track.risk_motion.motion_jump 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_linear.rst: -------------------------------------------------------------------------------- 1 | motion_linear 2 | ============= 3 | 4 | 5 | .. automodule:: robot_mouse_track.risk_motion.motion_linear 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_similar.rst: -------------------------------------------------------------------------------- 1 | motion_similar 2 | ============== 3 | 4 | 5 | .. automodule:: robot_mouse_track.risk_motion.motion_similar 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_slow.rst: -------------------------------------------------------------------------------- 1 | motion_slow 2 | ============= 3 | 4 | 5 | .. automodule:: robot_mouse_track.risk_motion.motion_slow 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/source/risk_motion/motion_vertical_horizontal_linear.rst: -------------------------------------------------------------------------------- 1 | motion_vertical_horizontal_linear 2 | ================================== 3 | 4 | .. automodule:: robot_mouse_track.risk_motion.motion_vertical_horizontal_linear 5 | :members: 6 | -------------------------------------------------------------------------------- /examples/collect_data.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Title 5 | 57 | 58 | 59 |

在线网络考试demo:

60 |

question1

61 | A.xxxxx
62 | 63 | B.xxxxx
64 | C.xxxxx
65 | D.xxxxx
66 |
67 |

question2

68 | A.xxxxx
69 | B.xxxxx
70 | C.xxxxx
71 | D.xxxxx
72 |
73 |

question3

74 | A.xxxxx
75 | B.xxxxx
76 | C.xxxxx
77 | D.xxxxx
78 |


79 |

滑块验证码demo:

80 |
81 |
>>
82 |

拖动滑块完成验证

83 |
84 |
85 |
86 |
87 | 88 | 89 | 90 | 110 | 111 | 112 | 153 | 154 | 155 | 156 | 157 | 158 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /examples/example_feature_vis.py: -------------------------------------------------------------------------------- 1 | from examples.trace_examples import trace_answer_unlock 2 | from robot_mouse_track.mouse_track import MouseTrack 3 | 4 | import matplotlib.pyplot as plt 5 | 6 | if __name__ == '__main__': 7 | mouse_track = MouseTrack(trace_answer_unlock) 8 | 9 | # 展示鼠标轨迹 10 | mouse_track.show_track() 11 | 12 | # 展示合速度 13 | feature_dev_order1, feature_dev_order2 = mouse_track.get_feature_dev(order=2, mode="combine") # contants.COMBINE 14 | plt.plot(mouse_track.arr_trace[:len(feature_dev_order1),-1], feature_dev_order1) 15 | plt.xlabel("time") 16 | plt.ylabel("px/ms") 17 | plt.show() 18 | # 19 | # plt.plot(mouse_track.arr_trace[:len(feature_dev_order2),-1], feature_dev_order2) 20 | # plt.xlabel("time") 21 | # plt.ylabel("px/ms^2") 22 | # plt.show() 23 | 24 | # 展示分速度 25 | # feature_dev_order1, feature_dev_order2 = mouse_track.get_feature_dev(order=2, mode="decomposition") # contants.COMBINE 26 | # plt.plot(mouse_track.arr_trace[:len(feature_dev_order1), -1], feature_dev_order1[:, 0]) 27 | # plt.xlabel("time") 28 | # plt.ylabel("x-axis px/ms") 29 | # plt.show() 30 | 31 | feature_doa = mouse_track.get_feature_doa() 32 | plt.plot(mouse_track.arr_trace[:len(feature_doa), -1], feature_doa) 33 | plt.xlabel("time") 34 | plt.ylabel("angle") 35 | plt.show() 36 | -------------------------------------------------------------------------------- /examples/example_motion_jump.py: -------------------------------------------------------------------------------- 1 | from examples.trace_examples import trace_selenium_jump 2 | from robot_mouse_track.mouse_track import MouseTrack 3 | from robot_mouse_track.risk_motion.motion_jump import JumpMotion 4 | 5 | if __name__ == '__main__': 6 | mouse_track = MouseTrack(trace_selenium_jump) 7 | mouse_track.show_track() 8 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 9 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 10 | print(flag,exceed_times_velocity,exceed_times_acceleration) 11 | 12 | -------------------------------------------------------------------------------- /examples/example_rules.py: -------------------------------------------------------------------------------- 1 | from examples.trace_examples import trace_itmorn, trace_answer_unlock 2 | from robot_mouse_track.mouse_track import MouseTrack 3 | from robot_mouse_track.risk_motion.motion_jump import JumpMotion 4 | from robot_mouse_track.risk_motion.motion_vertical_horizontal_linear import VerticalHorizontalLinearMotion 5 | from robot_mouse_track.risk_motion.motion_linear import LinearMotion 6 | from robot_mouse_track.risk_motion.motion_constant_velocity import ConstantVelocityMotion 7 | from robot_mouse_track.risk_motion.motion_slow import SlowMotion 8 | from robot_mouse_track.risk_motion.motion_similar import SimilarMotion, calc_vec 9 | 10 | 11 | if __name__ == '__main__': 12 | mouse_track = MouseTrack(trace_itmorn) 13 | mouse_track.show_track() 14 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 15 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 16 | print(flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration) 17 | 18 | rule_mouse_jump = VerticalHorizontalLinearMotion() 19 | flag, (exceed_times_x, exceed_times_y) = rule_mouse_jump.judge_risk(mouse_track) 20 | print(flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y) 21 | 22 | rule_mouse_jump = LinearMotion() 23 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 24 | print(flag, "LinearMotion", exceed_times) 25 | 26 | rule_mouse_jump = ConstantVelocityMotion() 27 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 28 | print(flag, "ConstantVelocityMotion", exceed_times) 29 | 30 | rule_mouse = SlowMotion() 31 | flag, exceed_times = rule_mouse.judge_risk(mouse_track) 32 | print(flag, "SlowMotion", exceed_times) 33 | 34 | lst_vec_bank = [] 35 | mouse_track1 = MouseTrack(trace_itmorn) 36 | vec1 = calc_vec(mouse_track1) 37 | lst_vec_bank.append(vec1) 38 | 39 | mouse_track2 = MouseTrack(trace_answer_unlock) 40 | vec_now = calc_vec(mouse_track2) 41 | 42 | rule_mouse = SimilarMotion() 43 | flag, exceed_times = rule_mouse.judge_risk(vec=vec_now, lst_vec_bank=lst_vec_bank) 44 | print(flag, "SimilarMotion", exceed_times) 45 | -------------------------------------------------------------------------------- /examples/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | from flask import request 3 | from flask_cors import CORS 4 | 5 | from examples.trace_examples import trace_itmorn, trace_answer_unlock 6 | from robot_mouse_track.mouse_track import MouseTrack 7 | from robot_mouse_track.risk_motion.motion_jump import JumpMotion 8 | from robot_mouse_track.risk_motion.motion_vertical_horizontal_linear import VerticalHorizontalLinearMotion 9 | from robot_mouse_track.risk_motion.motion_linear import LinearMotion 10 | from robot_mouse_track.risk_motion.motion_constant_velocity import ConstantVelocityMotion 11 | from robot_mouse_track.risk_motion.motion_slow import SlowMotion 12 | from robot_mouse_track.risk_motion.motion_similar import SimilarMotion, calc_vec 13 | 14 | app = Flask(__name__) 15 | CORS(app, supports_credentials=True) # 设置跨域 16 | 17 | 18 | @app.route("/predict", methods=["POST"]) 19 | def index(): 20 | trace = request.get_json() 21 | print(trace) 22 | mouse_track = MouseTrack(trace) 23 | mouse_track.show_track() 24 | lst_res = [] 25 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 26 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 27 | print(flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration) 28 | lst_res.append([flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration]) 29 | 30 | rule_mouse_jump = VerticalHorizontalLinearMotion() 31 | flag, (exceed_times_x, exceed_times_y) = rule_mouse_jump.judge_risk(mouse_track) 32 | print(flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y) 33 | lst_res.append([flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y]) 34 | 35 | rule_mouse_jump = LinearMotion() 36 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 37 | print(flag, "LinearMotion", exceed_times) 38 | lst_res.append([flag, "LinearMotion", exceed_times]) 39 | 40 | rule_mouse_jump = ConstantVelocityMotion() 41 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 42 | print(flag, "ConstantVelocityMotion", exceed_times) 43 | lst_res.append([flag, "ConstantVelocityMotion", exceed_times]) 44 | 45 | rule_mouse = SlowMotion() 46 | flag, exceed_times = rule_mouse.judge_risk(mouse_track) 47 | print(flag, "SlowMotion", exceed_times) 48 | lst_res.append([flag, "SlowMotion", exceed_times]) 49 | 50 | lst_vec_bank = [] 51 | mouse_track1 = MouseTrack(trace_itmorn) 52 | vec1 = calc_vec(mouse_track1) 53 | lst_vec_bank.append(vec1) 54 | 55 | mouse_track2 = MouseTrack(trace_answer_unlock) 56 | vec_now = calc_vec(mouse_track2) 57 | 58 | rule_mouse = SimilarMotion() 59 | flag, exceed_times = rule_mouse.judge_risk(vec=vec_now, lst_vec_bank=lst_vec_bank) 60 | print(flag, "SimilarMotion", exceed_times) 61 | lst_res.append([flag, "SimilarMotion", exceed_times]) 62 | 63 | return jsonify(lst_res) 64 | 65 | 66 | if __name__ == '__main__': 67 | app.run() 68 | -------------------------------------------------------------------------------- /examples/trace_examples.py: -------------------------------------------------------------------------------- 1 | # 手工绘制itmorn的LOGO 2 | trace_itmorn = [[404, 0, 1655035839721], [409, 11, 1655035839734], [420, 29, 1655035839748], [425, 40, 1655035839761], [436, 59, 1655035839774], [443, 71, 1655035839788], [454, 90, 1655035839801], [458, 98, 1655035839814], [468, 113, 1655035839827], [474, 122, 1655035839841], [480, 131, 1655035839854], [483, 134, 1655035839868], [484, 136, 1655035839881], [484, 137, 1655035840098], [479, 139, 1655035840107], [474, 140, 1655035840121], [467, 142, 1655035840134], [450, 146, 1655035840148], [444, 147, 1655035840161], [427, 149, 1655035840174], [421, 150, 1655035840188], [420, 150, 1655035840201], [420, 151, 1655035840214], [422, 151, 1655035840254], [428, 151, 1655035840268], [440, 151, 1655035840281], [452, 151, 1655035840294], [470, 150, 1655035840308], [479, 150, 1655035840321], [492, 149, 1655035840334], [498, 149, 1655035840348], [508, 149, 1655035840361], [511, 150, 1655035840375], [513, 152, 1655035840388], [513, 153, 1655035840401], [513, 156, 1655035840414], [513, 158, 1655035840428], [513, 159, 1655035840441], [507, 166, 1655035840454], [495, 184, 1655035840468], [481, 209, 1655035840481], [463, 239, 1655035840494], [450, 258, 1655035840508], [433, 283, 1655035840521], [429, 289, 1655035840535], [417, 307, 1655035840548], [407, 324, 1655035840561], [403, 334, 1655035840574], [402, 338, 1655035840588], [402, 346, 1655035840601], [402, 349, 1655035840615], [403, 350, 1655035840628], [405, 352, 1655035840641], [412, 352, 1655035840655], [421, 349, 1655035840668], [435, 343, 1655035840681], [449, 337, 1655035840694], [461, 330, 1655035840708], [472, 326, 1655035840721], [476, 323, 1655035840735], [485, 320, 1655035840749], [490, 319, 1655035840761], [491, 319, 1655035840775], [491, 318, 1655035840824], [491, 317, 1655035840888], [492, 316, 1655035840895], [493, 313, 1655035840908], [498, 301, 1655035840921], [504, 292, 1655035840935], [515, 273, 1655035840949], [523, 260, 1655035840961], [525, 254, 1655035840975], [528, 244, 1655035840988], [529, 241, 1655035841001], [533, 226, 1655035841015], [536, 218, 1655035841028], [536, 215, 1655035841041], [537, 211, 1655035841055], [537, 208, 1655035841068], [537, 205, 1655035841081], [537, 204, 1655035841095], [536, 201, 1655035841108], [536, 200, 1655035841121], [536, 198, 1655035841135], [535, 198, 1655035841175], [537, 198, 1655035841218], [540, 198, 1655035841228], [548, 197, 1655035841242], [556, 197, 1655035841255], [575, 194, 1655035841268], [581, 194, 1655035841281], [593, 191, 1655035841295], [597, 190, 1655035841308], [601, 189, 1655035841322], [602, 189, 1655035841335], [602, 188, 1655035841375], [602, 187, 1655035841388], [602, 186, 1655035841404], [602, 185, 1655035841416], [602, 181, 1655035841429], [600, 177, 1655035841442], [596, 164, 1655035841455], [591, 144, 1655035841468], [590, 140, 1655035841482], [590, 129, 1655035841495], [590, 123, 1655035841508], [589, 117, 1655035841522], [589, 110, 1655035841535], [589, 107, 1655035841548], [589, 102, 1655035841562], [589, 98, 1655035841575], [589, 96, 1655035841588], [589, 94, 1655035841602], [589, 95, 1655035841724], [588, 98, 1655035841735], [588, 100, 1655035841749], [588, 105, 1655035841762], [587, 114, 1655035841775], [587, 115, 1655035841788], [585, 123, 1655035841802], [584, 129, 1655035841815], [583, 133, 1655035841829], [582, 140, 1655035841842], [581, 144, 1655035841855], [580, 153, 1655035841869], [579, 160, 1655035841882], [578, 170, 1655035841895], [578, 174, 1655035841908], [577, 182, 1655035841922], [576, 187, 1655035841935], [575, 196, 1655035841949], [574, 209, 1655035841962], [573, 221, 1655035841975], [573, 229, 1655035841988], [572, 243, 1655035842002], [571, 251, 1655035842016], [570, 267, 1655035842028], [570, 274, 1655035842042], [570, 279, 1655035842055], [570, 282, 1655035842068], [570, 286, 1655035842082], [570, 287, 1655035842095], [570, 291, 1655035842109], [570, 292, 1655035842122], [570, 295, 1655035842135], [570, 297, 1655035842149], [570, 299, 1655035842162], [570, 300, 1655035842175], [572, 302, 1655035842189], [573, 303, 1655035842202], [575, 304, 1655035842215], [582, 305, 1655035842229], [588, 306, 1655035842242], [592, 306, 1655035842255], [603, 306, 1655035842268], [609, 306, 1655035842282], [610, 306, 1655035842296], [611, 306, 1655035842309], [611, 305, 1655035842608], [613, 301, 1655035842616], [619, 292, 1655035842629], [622, 290, 1655035842642], [633, 278, 1655035842655], [637, 273, 1655035842669], [649, 255, 1655035842682], [664, 227, 1655035842696], [668, 217, 1655035842709], [676, 199, 1655035842722], [681, 183, 1655035842735], [682, 178, 1655035842749], [684, 174, 1655035842762], [685, 167, 1655035842775], [685, 165, 1655035842789], [685, 163, 1655035842802], [685, 160, 1655035842816], [685, 159, 1655035842829], [684, 156, 1655035842842], [683, 149, 1655035842855], [683, 147, 1655035842869], [683, 144, 1655035842882], [683, 141, 1655035842897], [683, 140, 1655035842918], [684, 139, 1655035842941], [687, 139, 1655035842963], [692, 145, 1655035842976], [694, 149, 1655035842989], [700, 163, 1655035843002], [705, 186, 1655035843016], [706, 194, 1655035843029], [706, 218, 1655035843043], [706, 227, 1655035843056], [706, 248, 1655035843069], [703, 284, 1655035843083], [700, 297, 1655035843096], [696, 316, 1655035843109], [695, 325, 1655035843122], [694, 327, 1655035843136], [694, 320, 1655035843190], [694, 306, 1655035843203], [696, 285, 1655035843216], [697, 273, 1655035843229], [699, 264, 1655035843243], [701, 237, 1655035843256], [706, 207, 1655035843274], [709, 194, 1655035843288], [711, 184, 1655035843297], [714, 172, 1655035843311], [717, 164, 1655035843322], [718, 162, 1655035843335], [719, 160, 1655035843349], [720, 159, 1655035843362], [721, 159, 1655035843375], [722, 159, 1655035843388], [724, 159, 1655035843402], [725, 159, 1655035843415], [729, 161, 1655035843429], [733, 172, 1655035843442], [735, 182, 1655035843455], [736, 197, 1655035843468], [736, 225, 1655035843482], [736, 242, 1655035843495], [736, 258, 1655035843510], [736, 266, 1655035843523], [736, 285, 1655035843536], [736, 303, 1655035843550], [736, 310, 1655035843563], [736, 315, 1655035843576], [736, 316, 1655035843589], [736, 315, 1655035843616], [736, 313, 1655035843630], [736, 298, 1655035843643], [738, 265, 1655035843656], [740, 239, 1655035843669], [742, 227, 1655035843683], [748, 205, 1655035843696], [750, 196, 1655035843709], [754, 185, 1655035843723], [755, 177, 1655035843736], [757, 167, 1655035843749], [759, 163, 1655035843763], [762, 157, 1655035843777], [764, 154, 1655035843789], [768, 151, 1655035843803], [772, 148, 1655035843817], [774, 146, 1655035843829], [775, 146, 1655035843843], [776, 146, 1655035843856], [778, 146, 1655035843869], [780, 146, 1655035843883], [781, 146, 1655035843896], [785, 147, 1655035843910], [788, 149, 1655035843923], [792, 154, 1655035843936], [797, 159, 1655035843949], [800, 163, 1655035843963], [801, 165, 1655035843976], [805, 170, 1655035843990], [807, 174, 1655035844003], [808, 179, 1655035844016], [809, 190, 1655035844029], [810, 194, 1655035844043], [810, 198, 1655035844056], [810, 207, 1655035844070], [811, 217, 1655035844083], [811, 226, 1655035844096], [811, 234, 1655035844109], [811, 239, 1655035844123], [810, 247, 1655035844136], [809, 253, 1655035844150], [809, 262, 1655035844163], [807, 270, 1655035844178], [807, 274, 1655035844190], [807, 281, 1655035844205], [807, 289, 1655035844218], [807, 292, 1655035844230], [807, 295, 1655035844243], [808, 299, 1655035844256], [808, 300, 1655035844270], [808, 299, 1655035844369], [807, 295, 1655035844390], [806, 294, 1655035844404], [812, 289, 1655035844750], [820, 284, 1655035844763], [820, 283, 1655035844777], [821, 283, 1655035844790], [822, 283, 1655035844803], [824, 283, 1655035844818], [824, 284, 1655035844857], [829, 286, 1655035844871], [835, 289, 1655035844883], [847, 289, 1655035844898], [866, 288, 1655035844910], [878, 285, 1655035844923], [897, 276, 1655035844937], [910, 264, 1655035844950], [921, 248, 1655035844963], [927, 238, 1655035844976], [941, 206, 1655035844990], [946, 193, 1655035845003], [949, 185, 1655035845017], [953, 171, 1655035845031], [955, 158, 1655035845043], [955, 148, 1655035845057], [955, 143, 1655035845070], [954, 142, 1655035845083], [951, 141, 1655035845098], [946, 140, 1655035845110], [943, 140, 1655035845124], [938, 140, 1655035845137], [929, 146, 1655035845150], [924, 150, 1655035845163], [920, 157, 1655035845177], [916, 171, 1655035845190], [915, 182, 1655035845204], [915, 212, 1655035845217], [915, 222, 1655035845231], [916, 244, 1655035845245], [919, 263, 1655035845257], [924, 275, 1655035845270], [927, 279, 1655035845283], [930, 282, 1655035845298], [940, 285, 1655035845312], [951, 285, 1655035845323], [963, 283, 1655035845337], [969, 280, 1655035845351], [983, 271, 1655035845364], [993, 263, 1655035845377], [999, 257, 1655035845390], [1005, 247, 1655035845403], [1012, 228, 1655035845417], [1012, 222, 1655035845431], [1014, 200, 1655035845445], [1014, 181, 1655035845462], [1014, 167, 1655035845472], [1013, 161, 1655035845484], [1011, 156, 1655035845498], [1008, 150, 1655035845511], [1003, 145, 1655035845524], [999, 143, 1655035845537], [994, 143, 1655035845550], [987, 142, 1655035845564], [982, 141, 1655035845578], [965, 140, 1655035845590], [953, 140, 1655035845604], [947, 140, 1655035845620], [941, 140, 1655035845632], [939, 140, 1655035845647], [937, 141, 1655035845658], [936, 143, 1655035845688], [936, 144, 1655035845709], [936, 145, 1655035845917], [940, 147, 1655035845989], [949, 150, 1655035846007], [952, 150, 1655035846018], [968, 155, 1655035846030], [978, 158, 1655035846046], [985, 159, 1655035846058], [996, 160, 1655035846070], [1014, 162, 1655035846084], [1021, 162, 1655035846097], [1033, 162, 1655035846112], [1042, 162, 1655035846124], [1059, 162, 1655035846137], [1069, 162, 1655035846151], [1083, 159, 1655035846164], [1086, 157, 1655035846178], [1088, 156, 1655035846191], [1089, 154, 1655035846204], [1090, 151, 1655035846217], [1090, 150, 1655035846232], [1090, 147, 1655035846245], [1090, 145, 1655035846257], [1090, 142, 1655035846271], [1087, 140, 1655035846310], [1086, 139, 1655035846322], [1087, 139, 1655035846383], [1088, 141, 1655035846393], [1089, 146, 1655035846405], [1092, 157, 1655035846418], [1093, 165, 1655035846432], [1095, 185, 1655035846445], [1099, 204, 1655035846457], [1100, 213, 1655035846471], [1103, 238, 1655035846484], [1103, 246, 1655035846498], [1103, 272, 1655035846511], [1103, 290, 1655035846525], [1103, 294, 1655035846538], [1103, 291, 1655035846591], [1103, 284, 1655035846604], [1103, 279, 1655035846618], [1103, 274, 1655035846632], [1105, 254, 1655035846647], [1110, 221, 1655035846664], [1116, 190, 1655035846681], [1119, 174, 1655035846696], [1124, 163, 1655035846716], [1129, 155, 1655035846730], [1134, 151, 1655035846744], [1141, 149, 1655035846757], [1153, 149, 1655035846770], [1169, 149, 1655035846790], [1182, 150, 1655035846807], [1192, 151, 1655035846819], [1196, 152, 1655035846830], [1198, 153, 1655035846843], [1199, 153, 1655035847148], [1207, 152, 1655035847164], [1210, 152, 1655035847179], [1218, 151, 1655035847193], [1223, 150, 1655035847205], [1231, 146, 1655035847218], [1233, 145, 1655035847231], [1235, 142, 1655035847245], [1235, 141, 1655035847258], [1235, 137, 1655035847271], [1235, 136, 1655035847284], [1235, 134, 1655035847299], [1235, 132, 1655035847313], [1235, 131, 1655035847324], [1235, 130, 1655035847351], [1235, 129, 1655035847365], [1237, 129, 1655035847398], [1238, 130, 1655035847410], [1241, 134, 1655035847423], [1244, 139, 1655035847436], [1251, 150, 1655035847450], [1258, 159, 1655035847462], [1261, 163, 1655035847474], [1266, 170, 1655035847487], [1272, 185, 1655035847501], [1277, 214, 1655035847514], [1277, 226, 1655035847527], [1277, 246, 1655035847539], [1274, 256, 1655035847551], [1268, 271, 1655035847565], [1260, 282, 1655035847579], [1256, 287, 1655035847593], [1254, 288, 1655035847606], [1254, 287, 1655035847641], [1254, 279, 1655035847654], [1254, 265, 1655035847666], [1256, 252, 1655035847681], [1259, 236, 1655035847694], [1263, 219, 1655035847712], [1270, 201, 1655035847725], [1274, 191, 1655035847738], [1278, 178, 1655035847755], [1280, 172, 1655035847769], [1283, 163, 1655035847783], [1284, 158, 1655035847797], [1285, 157, 1655035847810], [1285, 156, 1655035847823], [1286, 154, 1655035847836], [1287, 153, 1655035847850], [1287, 152, 1655035847871], [1288, 152, 1655035847886], [1289, 151, 1655035847899], [1290, 151, 1655035847917], [1291, 151, 1655035847930], [1292, 151, 1655035847952], [1296, 151, 1655035847968], [1301, 155, 1655035847982], [1304, 156, 1655035847996], [1309, 159, 1655035848008], [1312, 160, 1655035848022], [1314, 162, 1655035848038], [1315, 167, 1655035848052], [1316, 171, 1655035848066], [1317, 180, 1655035848080], [1318, 192, 1655035848095], [1319, 201, 1655035848110], [1319, 209, 1655035848125], [1320, 215, 1655035848138], [1321, 225, 1655035848152], [1321, 241, 1655035848178], [1321, 249, 1655035848192], [1320, 259, 1655035848205], [1320, 262, 1655035848218], [1320, 269, 1655035848232], [1320, 275, 1655035848249], [1321, 281, 1655035848264], [1323, 285, 1655035848279], [1324, 286, 1655035848292], [1327, 288, 1655035848306], [1336, 291, 1655035848321], [1347, 292, 1655035848338], [1358, 292, 1655035848352], [1366, 291, 1655035848366], [1371, 289, 1655035848379], [1376, 286, 1655035848393], [1377, 285, 1655035848409], [1378, 285, 1655035848729], [1379, 285, 1655035848752], [1380, 285, 1655035848767], [1381, 285, 1655035848782], [1378, 286, 1655035848955], [1359, 297, 1655035848970], [1337, 307, 1655035848983], [1291, 324, 1655035848996], [1231, 347, 1655035849011], [1198, 360, 1655035849026], [1091, 408, 1655035849041], [969, 450, 1655035849055], [830, 488, 1655035849068], [696, 518, 1655035849084], [601, 539, 1655035849100], [545, 551, 1655035849115], [468, 567, 1655035849129], [408, 581, 1655035849143], [363, 592, 1655035849159], [336, 601, 1655035849179], [329, 604, 1655035849193], [319, 613, 1655035849209], [304, 630, 1655035849231], [293, 639, 1655035849246], [283, 646, 1655035849260], [265, 655, 1655035849274], [238, 669, 1655035849290], [223, 676, 1655035849306], [205, 683, 1655035849321], [194, 688, 1655035849336], [185, 693, 1655035849352], [168, 698, 1655035849372], [162, 699, 1655035849386], [153, 700, 1655035849400], [140, 701, 1655035849411], [122, 703, 1655035849421], [112, 704, 1655035849431], [106, 704, 1655035849445], [93, 706, 1655035849459], [81, 706, 1655035849475], [69, 709, 1655035849493], [58, 710, 1655035849509], [47, 710, 1655035849525], [43, 710, 1655035849542], [39, 710, 1655035849559], [38, 710, 1655035849573], [37, 710, 1655035849588], [36, 710, 1655035849606], [35, 711, 1655035849621], [32, 714, 1655035849639], [27, 717, 1655035849654], [23, 719, 1655035849669], [21, 721, 1655035849683], [21, 723, 1655035849700]] 3 | 4 | # 机器跳跃式作答,解验证码,提交 5 | trace_selenium_jump = [[6, 83, 1655038106398], [6, 240, 1655038107474], [6, 376, 1655038108650], [285, 601, 1655038109698], [305, 601, 1655038110224], [325, 601, 1655038110738], [345, 601, 1655038111263], [365, 601, 1655038111782], [385, 601, 1655038112307], [405, 601, 1655038112831], [425, 601, 1655038113342], [445, 601, 1655038113884], [465, 601, 1655038114396], [485, 601, 1655038114921], [505, 601, 1655038115453], [525, 601, 1655038115973], [545, 601, 1655038116500], [565, 601, 1655038117035], [585, 601, 1655038117566], [605, 601, 1655038118095], [625, 601, 1655038118635], [645, 601, 1655038119177], [15, 721, 1655038120794]] 6 | 7 | # 手工作答,解验证码,提交 8 | trace_answer_unlock = [[72, 0, 1655046417887], [72, 1, 1655046417903], [70, 3, 1655046417916], [69, 5, 1655046417930], [68, 6, 1655046417951], [67, 8, 1655046417983], [67, 10, 1655046417996], [65, 15, 1655046418010], [62, 20, 1655046418023], [61, 23, 1655046418036], [59, 26, 1655046418049], [59, 27, 1655046418063], [57, 29, 1655046418076], [55, 31, 1655046418089], [54, 32, 1655046418103], [52, 34, 1655046418116], [49, 38, 1655046418129], [46, 40, 1655046418143], [42, 45, 1655046418156], [37, 50, 1655046418170], [34, 53, 1655046418183], [33, 55, 1655046418196], [30, 56, 1655046418210], [27, 57, 1655046418223], [27, 58, 1655046418236], [26, 58, 1655046418250], [24, 60, 1655046418263], [22, 63, 1655046418276], [19, 67, 1655046418290], [19, 68, 1655046418303], [18, 70, 1655046418316], [17, 71, 1655046418330], [17, 72, 1655046418345], [17, 73, 1655046418361], [17, 74, 1655046418435], [15, 75, 1655046418463], [13, 76, 1655046418476], [12, 77, 1655046418490], [11, 77, 1655046418503], [9, 78, 1655046418516], [9, 79, 1655046418530], [8, 79, 1655046418543], [7, 79, 1655046418583], [7, 80, 1655046418596], [7, 81, 1655046418818], [7, 84, 1655046418828], [7, 88, 1655046418836], [7, 94, 1655046418850], [6, 94, 1655046419230], [6, 95, 1655046419238], [5, 95, 1655046419249], [5, 96, 1655046419263], [5, 97, 1655046419276], [5, 103, 1655046419289], [5, 106, 1655046419303], [5, 108, 1655046419316], [5, 114, 1655046419330], [5, 121, 1655046419343], [5, 124, 1655046419356], [5, 131, 1655046419369], [6, 137, 1655046419383], [6, 139, 1655046419396], [6, 148, 1655046419409], [6, 150, 1655046419423], [7, 154, 1655046419436], [8, 157, 1655046419450], [8, 159, 1655046419463], [8, 162, 1655046419476], [8, 165, 1655046419489], [8, 167, 1655046419503], [9, 169, 1655046419516], [9, 171, 1655046419530], [9, 173, 1655046419543], [9, 175, 1655046419556], [9, 179, 1655046419570], [9, 180, 1655046419583], [9, 184, 1655046419596], [9, 188, 1655046419610], [9, 190, 1655046419623], [9, 194, 1655046419636], [9, 197, 1655046419650], [9, 198, 1655046419671], [9, 199, 1655046419688], [9, 200, 1655046419705], [9, 201, 1655046419716], [9, 202, 1655046419730], [9, 203, 1655046419745], [9, 204, 1655046419769], [9, 205, 1655046419793], [9, 206, 1655046419801], [9, 208, 1655046419809], [9, 209, 1655046419823], [9, 212, 1655046419836], [10, 214, 1655046419850], [10, 215, 1655046419863], [10, 216, 1655046419877], [11, 216, 1655046419890], [11, 217, 1655046419903], [11, 218, 1655046419916], [11, 219, 1655046419930], [11, 220, 1655046420560], [11, 221, 1655046420571], [12, 227, 1655046420583], [12, 230, 1655046420597], [13, 236, 1655046420610], [13, 241, 1655046420623], [13, 242, 1655046420637], [13, 245, 1655046420650], [13, 250, 1655046420663], [13, 253, 1655046420677], [13, 258, 1655046420690], [12, 264, 1655046420703], [12, 266, 1655046420717], [11, 269, 1655046420730], [11, 271, 1655046420744], [10, 274, 1655046420757], [10, 277, 1655046420770], [9, 282, 1655046420783], [9, 285, 1655046420797], [9, 291, 1655046420810], [8, 299, 1655046420823], [8, 302, 1655046420837], [8, 308, 1655046420850], [8, 314, 1655046420863], [8, 318, 1655046420877], [8, 322, 1655046420890], [8, 325, 1655046420904], [8, 328, 1655046420918], [8, 331, 1655046420931], [8, 334, 1655046420944], [8, 337, 1655046420958], [8, 339, 1655046420971], [8, 341, 1655046420984], [8, 343, 1655046420998], [8, 344, 1655046421013], [8, 345, 1655046421025], [8, 347, 1655046421038], [8, 348, 1655046421051], [8, 350, 1655046421064], [8, 352, 1655046421078], [8, 353, 1655046421092], [8, 355, 1655046421104], [8, 356, 1655046421118], [8, 359, 1655046421131], [9, 362, 1655046421145], [9, 366, 1655046421158], [9, 367, 1655046421171], [9, 369, 1655046421184], [9, 371, 1655046421198], [9, 372, 1655046421221], [9, 373, 1655046421342], [11, 373, 1655046421837], [21, 375, 1655046421865], [32, 377, 1655046421878], [49, 382, 1655046421892], [62, 386, 1655046421905], [92, 398, 1655046421918], [109, 410, 1655046421931], [145, 436, 1655046421945], [175, 452, 1655046421959], [214, 476, 1655046421972], [231, 486, 1655046421985], [277, 506, 1655046421998], [332, 524, 1655046422012], [358, 530, 1655046422025], [401, 540, 1655046422039], [461, 554, 1655046422052], [484, 559, 1655046422065], [537, 569, 1655046422078], [579, 574, 1655046422092], [599, 575, 1655046422106], [611, 576, 1655046422118], [637, 576, 1655046422132], [656, 577, 1655046422145], [666, 577, 1655046422158], [679, 578, 1655046422173], [695, 579, 1655046422186], [701, 579, 1655046422198], [712, 579, 1655046422211], [721, 579, 1655046422225], [723, 579, 1655046422239], [729, 579, 1655046422251], [733, 579, 1655046422265], [734, 580, 1655046422278], [736, 580, 1655046422292], [737, 580, 1655046422305], [737, 581, 1655046422358], [738, 582, 1655046422373], [740, 584, 1655046422385], [742, 587, 1655046422398], [743, 587, 1655046422414], [744, 589, 1655046422426], [748, 592, 1655046422438], [751, 595, 1655046422452], [755, 598, 1655046422465], [757, 599, 1655046422478], [757, 600, 1655046422492], [758, 600, 1655046422506], [759, 600, 1655046422518], [760, 600, 1655046422562], [761, 600, 1655046422577], [762, 600, 1655046422587], [763, 600, 1655046422598], [765, 600, 1655046422611], [766, 600, 1655046422625], [768, 600, 1655046422638], [769, 600, 1655046422651], [770, 600, 1655046422664], [771, 600, 1655046422678], [772, 600, 1655046422698], [773, 600, 1655046422706], [774, 600, 1655046422718], [777, 600, 1655046422732], [780, 600, 1655046422748], [781, 600, 1655046422761], [782, 600, 1655046422775], [783, 600, 1655046422825], [784, 600, 1655046422848], [785, 601, 1655046422884], [786, 601, 1655046422918], [789, 601, 1655046422932], [790, 601, 1655046422945], [793, 601, 1655046422959], [795, 601, 1655046422972], [796, 601, 1655046422985], [798, 601, 1655046422998], [799, 601, 1655046423012], [802, 601, 1655046423025], [803, 601, 1655046423039], [805, 601, 1655046423052], [807, 601, 1655046423065], [810, 601, 1655046423078], [811, 601, 1655046423092], [814, 601, 1655046423105], [815, 601, 1655046423118], [818, 601, 1655046423132], [820, 600, 1655046423145], [823, 600, 1655046423159], [826, 600, 1655046423173], [827, 600, 1655046423185], [830, 600, 1655046423198], [832, 600, 1655046423212], [834, 600, 1655046423225], [835, 600, 1655046423239], [838, 600, 1655046423252], [839, 600, 1655046423265], [844, 600, 1655046423278], [847, 600, 1655046423292], [850, 600, 1655046423305], [851, 600, 1655046423318], [856, 600, 1655046423332], [860, 600, 1655046423345], [866, 600, 1655046423359], [869, 600, 1655046423372], [872, 600, 1655046423386], [879, 600, 1655046423399], [882, 600, 1655046423412], [888, 600, 1655046423426], [892, 600, 1655046423438], [896, 600, 1655046423451], [898, 600, 1655046423464], [901, 600, 1655046423478], [906, 600, 1655046423491], [907, 600, 1655046423504], [911, 600, 1655046423518], [915, 600, 1655046423531], [917, 600, 1655046423544], [924, 600, 1655046423558], [926, 600, 1655046423571], [935, 600, 1655046423584], [937, 600, 1655046423598], [940, 600, 1655046423612], [943, 600, 1655046423625], [945, 600, 1655046423638], [947, 600, 1655046423652], [948, 600, 1655046423665], [951, 601, 1655046423679], [953, 601, 1655046423692], [956, 601, 1655046423705], [958, 601, 1655046423719], [961, 601, 1655046423732], [963, 601, 1655046423745], [966, 601, 1655046423759], [969, 602, 1655046423772], [972, 602, 1655046423785], [973, 602, 1655046423799], [974, 602, 1655046423812], [975, 602, 1655046423825], [977, 602, 1655046423839], [980, 602, 1655046423852], [981, 602, 1655046423865], [983, 602, 1655046423879], [986, 602, 1655046423892], [989, 602, 1655046423905], [993, 602, 1655046423919], [998, 602, 1655046423932], [1001, 602, 1655046423945], [1006, 602, 1655046423959], [1012, 602, 1655046423972], [1014, 602, 1655046423986], [1020, 602, 1655046423998], [1026, 602, 1655046424012], [1028, 602, 1655046424025], [1032, 602, 1655046424038], [1036, 602, 1655046424052], [1039, 602, 1655046424066], [1043, 602, 1655046424079], [1046, 602, 1655046424092], [1049, 602, 1655046424105], [1052, 602, 1655046424119], [1054, 602, 1655046424132], [1057, 602, 1655046424145], [1060, 602, 1655046424159], [1061, 602, 1655046424172], [1065, 602, 1655046424185], [1069, 602, 1655046424198], [1072, 602, 1655046424212], [1078, 602, 1655046424225], [1086, 602, 1655046424239], [1089, 602, 1655046424252], [1094, 603, 1655046424266], [1098, 603, 1655046424279], [1100, 603, 1655046424292], [1104, 603, 1655046424306], [1108, 603, 1655046424319], [1113, 603, 1655046424333], [1115, 603, 1655046424345], [1119, 603, 1655046424359], [1121, 603, 1655046424372], [1125, 603, 1655046424386], [1131, 603, 1655046424412], [1133, 603, 1655046424425], [1135, 603, 1655046424438], [1138, 603, 1655046424452], [1140, 603, 1655046424466], [1141, 603, 1655046424480], [1142, 603, 1655046424493], [1144, 603, 1655046424508], [1145, 604, 1655046424519], [1146, 604, 1655046424533], [1147, 604, 1655046424559], [1148, 604, 1655046424607], [1149, 604, 1655046424625], [1150, 604, 1655046424639], [1151, 605, 1655046424655], [1152, 605, 1655046424705], [1154, 605, 1655046424719], [1155, 605, 1655046424733], [1156, 605, 1655046424745], [1156, 605, 1655046424840], [1156, 606, 1655046424859], [1152, 606, 1655046424868], [1143, 607, 1655046424878], [1124, 613, 1655046424891], [1105, 618, 1655046424905], [1073, 627, 1655046424918], [1034, 638, 1655046424932], [1025, 641, 1655046424945], [984, 649, 1655046424958], [941, 656, 1655046424972], [902, 662, 1655046424985], [829, 670, 1655046424998], [790, 674, 1655046425012], [715, 684, 1655046425025], [655, 686, 1655046425038], [611, 689, 1655046425052], [589, 690, 1655046425065], [527, 695, 1655046425078], [506, 697, 1655046425092], [452, 700, 1655046425105], [403, 703, 1655046425119], [389, 705, 1655046425132], [355, 709, 1655046425145], [319, 711, 1655046425159], [309, 711, 1655046425172], [279, 711, 1655046425186], [260, 711, 1655046425199], [252, 711, 1655046425212], [234, 711, 1655046425225], [219, 712, 1655046425239], [212, 712, 1655046425252], [193, 712, 1655046425265], [171, 713, 1655046425279], [165, 713, 1655046425292], [153, 715, 1655046425306], [138, 716, 1655046425318], [132, 717, 1655046425333], [122, 718, 1655046425347], [114, 718, 1655046425360], [102, 718, 1655046425373], [94, 718, 1655046425387], [84, 718, 1655046425402], [71, 719, 1655046425416], [67, 719, 1655046425428], [55, 719, 1655046425441], [44, 719, 1655046425456], [35, 719, 1655046425472], [31, 719, 1655046425484], [27, 719, 1655046425495], [26, 719, 1655046425506], [25, 719, 1655046425520], [24, 719, 1655046425536]] 9 | 10 | 11 | 12 | 13 | # trace1 = [[137, 6, 1654351304588], [137, 6, 1654351304591], [155, 22, 1654351304596], [167, 31, 1654351304600], [188, 46, 1654351304611], [214, 63, 1654351304617], [242, 78, 1654351304625], [267, 89, 1654351304630], [290, 100, 1654351304644], [314, 108, 1654351304654], [326, 113, 1654351304659], [343, 119, 1654351304668], [349, 121, 1654351304673], [358, 125, 1654351304681], [363, 127, 1654351304690], [365, 128, 1654351304697], [366, 128, 1654351304704], [367, 128, 1654351304712], [368, 128, 1654351304720], [368, 129, 1654351305101], [368, 130, 1654351305107], [366, 133, 1654351305115], [363, 137, 1654351305123], [361, 141, 1654351305133], [359, 146, 1654351305142], [353, 155, 1654351305149], [348, 164, 1654351305161], [345, 170, 1654351305165], [335, 182, 1654351305173], [331, 188, 1654351305181], [326, 195, 1654351305190], [317, 207, 1654351305197], [312, 215, 1654351305206], [303, 227, 1654351305213], [295, 238, 1654351305221], [287, 255, 1654351305229], [276, 272, 1654351305237], [268, 287, 1654351305247], [253, 311, 1654351305256], [248, 319, 1654351305264], [234, 336, 1654351305276], [225, 347, 1654351305282], [218, 354, 1654351305294], [214, 358, 1654351305301], [208, 364, 1654351305308], [202, 370, 1654351305318], [198, 373, 1654351305324], [196, 374, 1654351305336], [195, 375, 1654351305341], [194, 376, 1654351305351], [193, 376, 1654351305370], [193, 377, 1654351305376], [192, 377, 1654351305384], [192, 378, 1654351305402], [191, 378, 1654351305432], [192, 378, 1654351305560], [193, 378, 1654351305563], [195, 378, 1654351305570], [196, 378, 1654351305579], [197, 379, 1654351305586], [201, 379, 1654351305596], [204, 380, 1654351305603], [207, 380, 1654351305611], [212, 380, 1654351305619], [214, 381, 1654351305627], [220, 381, 1654351305634], [226, 381, 1654351305643], [232, 381, 1654351305650], [241, 381, 1654351305661], [253, 382, 1654351305667], [264, 382, 1654351305677], [272, 382, 1654351305683], [279, 382, 1654351305690], [287, 382, 1654351305699], [298, 382, 1654351305708], [306, 382, 1654351305717], [312, 382, 1654351305724], [324, 383, 1654351305733], [331, 383, 1654351305741], [338, 383, 1654351305749], [346, 383, 1654351305756], [358, 384, 1654351305771], [368, 384, 1654351305777], [378, 385, 1654351305786], [389, 385, 1654351305793], [397, 386, 1654351305802], [404, 386, 1654351305809], [411, 387, 1654351305818], [422, 388, 1654351305825], [429, 388, 1654351305835], [436, 389, 1654351305841], [441, 389, 1654351305849], [446, 390, 1654351305857], [455, 391, 1654351305868], [468, 392, 1654351305881], [472, 393, 1654351305888], [477, 393, 1654351305898], [481, 393, 1654351305903], [484, 393, 1654351305915], [485, 393, 1654351305921], [487, 393, 1654351305932], [488, 393, 1654351306004], [489, 393, 1654351306077], [489, 391, 1654351306146], [489, 388, 1654351306155], [489, 386, 1654351306162], [489, 382, 1654351306171], [488, 378, 1654351306178], [486, 373, 1654351306186], [485, 369, 1654351306195], [482, 362, 1654351306203], [481, 358, 1654351306211], [477, 353, 1654351306219], [474, 345, 1654351306226], [471, 339, 1654351306235], [469, 333, 1654351306245], [467, 329, 1654351306250], [464, 318, 1654351306262], [460, 309, 1654351306267], [458, 302, 1654351306281], [455, 294, 1654351306287], [453, 290, 1654351306297], [450, 285, 1654351306302], [449, 281, 1654351306313], [447, 277, 1654351306323], [445, 270, 1654351306336], [443, 265, 1654351306341], [441, 262, 1654351306351], [439, 256, 1654351306357], [436, 251, 1654351306368], [434, 247, 1654351306375], [432, 243, 1654351306379], [431, 238, 1654351306388], [429, 234, 1654351306400], [427, 229, 1654351306405], [426, 225, 1654351306418], [424, 219, 1654351306422], [422, 215, 1654351306430], [420, 210, 1654351306437], [419, 207, 1654351306449], [417, 203, 1654351306456], [413, 195, 1654351306467], [412, 191, 1654351306480], [411, 189, 1654351306488], [409, 185, 1654351306498], [407, 182, 1654351306502], [405, 180, 1654351306508], [403, 177, 1654351306514], [401, 174, 1654351306520], [400, 172, 1654351306530], [399, 170, 1654351306537], [397, 168, 1654351306544], [396, 165, 1654351306555], [395, 163, 1654351306562], [393, 161, 1654351306571], [392, 158, 1654351306579], [390, 157, 1654351306586], [388, 154, 1654351306597], [386, 152, 1654351306603], [385, 151, 1654351306611], [384, 149, 1654351306619], [382, 147, 1654351306627], [381, 145, 1654351306636], [381, 144, 1654351306643], [379, 143, 1654351306651], [379, 142, 1654351306659], [378, 141, 1654351306667], [377, 140, 1654351306676], [377, 139, 1654351306683], [376, 138, 1654351306691], [376, 137, 1654351306699], [375, 136, 1654351306715], [374, 135, 1654351306731], [374, 134, 1654351306739], [373, 134, 1654351306746], [373, 133, 1654351306756], [372, 132, 1654351306771], [372, 131, 1654351306811], [372, 130, 1654351306859], [371, 130, 1654351307035], [370, 129, 1654351307075], [369, 129, 1654351307123], [369, 128, 1654351307136], [368, 128, 1654351307155], [369, 128, 1654351307310], [371, 128, 1654351307316], [373, 128, 1654351307329], [374, 128, 1654351307336], [376, 128, 1654351307342], [380, 128, 1654351307350], [384, 128, 1654351307362], [388, 128, 1654351307377], [390, 128, 1654351307385], [392, 128, 1654351307393], [395, 129, 1654351307403], [400, 129, 1654351307410], [408, 129, 1654351307419], [411, 129, 1654351307428], [416, 129, 1654351307433], [419, 129, 1654351307440], [423, 129, 1654351307449], [428, 129, 1654351307457], [430, 129, 1654351307464], [436, 129, 1654351307473], [440, 129, 1654351307480], [446, 130, 1654351307490], [451, 130, 1654351307497], [455, 130, 1654351307508], [460, 130, 1654351307516], [468, 130, 1654351307524], [474, 130, 1654351307532], [479, 130, 1654351307541], [487, 131, 1654351307548], [493, 131, 1654351307557], [500, 131, 1654351307565], [506, 131, 1654351307572], [511, 131, 1654351307587], [514, 131, 1654351307593], [520, 131, 1654351307603], [525, 132, 1654351307611], [533, 132, 1654351307618], [538, 132, 1654351307624], [545, 132, 1654351307635], [548, 132, 1654351307643], [557, 132, 1654351307652], [561, 132, 1654351307664], [570, 133, 1654351307673], [578, 133, 1654351307682], [581, 133, 1654351307689], [592, 133, 1654351307694], [599, 133, 1654351307698], [607, 133, 1654351307704], [612, 133, 1654351307711], [618, 133, 1654351307720], [622, 133, 1654351307730], [631, 134, 1654351307738], [638, 134, 1654351307749], [641, 134, 1654351307758], [646, 134, 1654351307766], [654, 134, 1654351307775], [659, 134, 1654351307782], [665, 134, 1654351307792], [672, 134, 1654351307801], [678, 134, 1654351307809], [684, 134, 1654351307813], [687, 134, 1654351307820], [700, 134, 1654351307826], [708, 134, 1654351307836], [713, 134, 1654351307843], [718, 134, 1654351307851], [722, 134, 1654351307859], [726, 134, 1654351307870], [732, 134, 1654351307876], [739, 134, 1654351307882], [744, 134, 1654351307892], [750, 134, 1654351307899], [753, 134, 1654351307906], [759, 134, 1654351307920], [764, 134, 1654351307928], [771, 134, 1654351307938], [778, 134, 1654351307946], [781, 134, 1654351307952], [783, 134, 1654351307959], [784, 134, 1654351307971], [785, 134, 1654351307979], [786, 134, 1654351307986], [787, 134, 1654351307993], [788, 134, 1654351308003], [789, 134, 1654351308026], [789, 135, 1654351308236], [788, 136, 1654351308249], [786, 138, 1654351308258], [784, 141, 1654351308266], [783, 142, 1654351308272], [781, 145, 1654351308280], [777, 149, 1654351308287], [775, 152, 1654351308300], [772, 156, 1654351308308], [770, 159, 1654351308317], [769, 162, 1654351308325], [766, 167, 1654351308332], [763, 173, 1654351308338], [759, 180, 1654351308346], [756, 184, 1654351308357], [754, 186, 1654351308365], [748, 193, 1654351308372], [741, 204, 1654351308387], [738, 210, 1654351308393], [735, 213, 1654351308398], [730, 224, 1654351308405], [726, 230, 1654351308412], [723, 236, 1654351308423], [718, 243, 1654351308427], [715, 250, 1654351308436], [711, 256, 1654351308442], [707, 263, 1654351308450], [704, 269, 1654351308460], [700, 276, 1654351308467], [697, 283, 1654351308475], [692, 290, 1654351308484], [687, 301, 1654351308490], [682, 308, 1654351308500], [678, 315, 1654351308506], [673, 325, 1654351308516], [668, 332, 1654351308522], [664, 339, 1654351308531], [660, 346, 1654351308539], [655, 352, 1654351308548], [651, 357, 1654351308562], [648, 364, 1654351308574], [645, 370, 1654351308583], [643, 374, 1654351308592], [639, 384, 1654351308603], [635, 393, 1654351308612], [631, 400, 1654351308620], [629, 405, 1654351308628], [627, 408, 1654351308637], [624, 413, 1654351308652], [622, 416, 1654351308667], [620, 419, 1654351308675], [617, 423, 1654351308690], [615, 424, 1654351308704], [615, 425, 1654351308710], [614, 426, 1654351308716], [614, 427, 1654351308727], [615, 427, 1654351308872], [616, 427, 1654351308882], [618, 427, 1654351308887], [619, 426, 1654351308896], [621, 426, 1654351308904], [622, 426, 1654351308913], [624, 426, 1654351308919], [627, 426, 1654351308931], [631, 426, 1654351308936], [635, 426, 1654351308944], [641, 426, 1654351308953], [644, 426, 1654351308961], [649, 426, 1654351308969], [655, 426, 1654351308977], [666, 426, 1654351308984], [669, 426, 1654351308992], [679, 426, 1654351308998], [687, 427, 1654351309008], [695, 428, 1654351309015], [705, 429, 1654351309024], [713, 429, 1654351309031], [719, 430, 1654351309043], [733, 431, 1654351309051], [738, 431, 1654351309060], [750, 432, 1654351309067], [755, 432, 1654351309076], [765, 433, 1654351309083], [774, 435, 1654351309091], [783, 436, 1654351309100], [789, 437, 1654351309109], [805, 440, 1654351309117], [812, 441, 1654351309126], [823, 441, 1654351309132], [830, 442, 1654351309142], [839, 443, 1654351309148], [845, 444, 1654351309157], [850, 444, 1654351309165], [858, 446, 1654351309176], [864, 446, 1654351309189], [868, 446, 1654351309199], [872, 446, 1654351309208], [877, 447, 1654351309220], [882, 447, 1654351309229], [885, 448, 1654351309237], [889, 448, 1654351309249], [890, 448, 1654351309258], [892, 448, 1654351309267], [893, 448, 1654351309276], [894, 448, 1654351309283], [894, 444, 1654351309396], [893, 439, 1654351309411], [892, 432, 1654351309431], [887, 419, 1654351309452], [887, 415, 1654351309466], [883, 406, 1654351309476], [875, 386, 1654351309487], [872, 378, 1654351309496], [870, 372, 1654351309507], [864, 358, 1654351309521], [858, 340, 1654351309532], [856, 336, 1654351309542], [853, 327, 1654351309552], [849, 316, 1654351309560], [849, 311, 1654351309569], [846, 304, 1654351309578], [845, 299, 1654351309587], [842, 292, 1654351309597], [840, 286, 1654351309606], [838, 284, 1654351309619], [834, 274, 1654351309631], [833, 270, 1654351309641], [830, 261, 1654351309651], [828, 255, 1654351309660], [827, 250, 1654351309669], [825, 246, 1654351309681], [822, 237, 1654351309694], [821, 233, 1654351309708], [819, 225, 1654351309719], [818, 222, 1654351309727], [816, 215, 1654351309732], [814, 211, 1654351309735], [814, 208, 1654351309740], [812, 203, 1654351309748], [811, 199, 1654351309763], [810, 197, 1654351309777], [810, 194, 1654351309789], [807, 187, 1654351309801], [807, 184, 1654351309812], [806, 180, 1654351309820], [805, 177, 1654351309830], [803, 171, 1654351309841], [803, 169, 1654351309850], [802, 167, 1654351309859], [802, 165, 1654351309869], [801, 162, 1654351309877], [800, 157, 1654351309886], [800, 154, 1654351309894], [800, 153, 1654351309899], [800, 151, 1654351309905], [799, 149, 1654351309914], [799, 147, 1654351309921], [799, 146, 1654351309930], [798, 144, 1654351309936], [798, 143, 1654351309946], [798, 142, 1654351309974], [798, 141, 1654351310086], [797, 139, 1654351310105], [797, 138, 1654351310120], [797, 137, 1654351310147], [796, 137, 1654351310223], [796, 136, 1654351310251], [796, 135, 1654351310335], [795, 135, 1654351310353], [795, 134, 1654351310385], [794, 134, 1654351310394], [793, 133, 1654351310409], [793, 132, 1654351310433], [792, 132, 1654351310449], [791, 132, 1654351310814], [789, 133, 1654351310825], [785, 135, 1654351310837], [769, 145, 1654351310849], [762, 150, 1654351310859], [742, 163, 1654351310869], [729, 171, 1654351310881], [694, 197, 1654351310894], [686, 204, 1654351310903], [670, 217, 1654351310912], [662, 225, 1654351310926], [649, 241, 1654351310941], [639, 259, 1654351310958], [630, 274, 1654351310968], [626, 283, 1654351310978], [622, 291, 1654351310991], [611, 314, 1654351311004], [608, 322, 1654351311014], [598, 341, 1654351311025], [594, 349, 1654351311035], [587, 360, 1654351311046], [577, 375, 1654351311053], [573, 382, 1654351311062], [567, 388, 1654351311068], [564, 393, 1654351311076], [557, 401, 1654351311100], [547, 414, 1654351311110], [531, 433, 1654351311118], [522, 443, 1654351311128], [514, 451, 1654351311136], [508, 457, 1654351311141], [497, 469, 1654351311148], [487, 477, 1654351311157], [479, 484, 1654351311164], [474, 488, 1654351311172], [466, 494, 1654351311179], [458, 499, 1654351311187], [448, 506, 1654351311195], [437, 513, 1654351311202], [429, 517, 1654351311212], [424, 520, 1654351311219], [404, 531, 1654351311226], [392, 537, 1654351311235], [384, 541, 1654351311242], [368, 550, 1654351311252], [358, 555, 1654351311259], [338, 566, 1654351311267], [323, 574, 1654351311280], [313, 581, 1654351311291], [296, 591, 1654351311301], [285, 598, 1654351311314], [265, 606, 1654351311326], [258, 608, 1654351311337], [239, 614, 1654351311347], [231, 616, 1654351311358], [225, 618, 1654351311369], [208, 625, 1654351311379], [202, 627, 1654351311389], [194, 631, 1654351311399], [182, 637, 1654351311409], [178, 640, 1654351311419], [169, 644, 1654351311434], [150, 654, 1654351311442], [146, 656, 1654351311447], [137, 662, 1654351311452], [129, 666, 1654351311458], [123, 669, 1654351311466], [118, 673, 1654351311473], [113, 675, 1654351311481], [112, 676, 1654351311490], [107, 679, 1654351311496], [105, 680, 1654351311506], [102, 682, 1654351311513], [100, 683, 1654351311520], [98, 685, 1654351311544], [96, 686, 1654351311559], [93, 689, 1654351311574], [86, 693, 1654351311589], [80, 696, 1654351311602], [68, 701, 1654351311614], [60, 704, 1654351311627], [55, 706, 1654351311637], [48, 709, 1654351311649], [45, 710, 1654351311659], [44, 711, 1654351311664], [43, 711, 1654351311672], [43, 712, 1654351311681], [42, 712, 1654351311690], [40, 713, 1654351311710], [39, 713, 1654351311726], [36, 714, 1654351311741], [31, 716, 1654351311752], [27, 717, 1654351311764], [24, 717, 1654351311776], [21, 719, 1654351311788], [20, 719, 1654351311803], [19, 720, 1654351311817], [18, 720, 1654351311830], [17, 720, 1654351311849]] 14 | # trace = [[117, 6, 1654351393762], [118, 17, 1654351393766], [119, 22, 1654351393770], [120, 28, 1654351393784], [123, 36, 1654351393789], [124, 42, 1654351393799], [126, 50, 1654351393806], [128, 56, 1654351393813], [130, 60, 1654351393819], [131, 64, 1654351393828], [131, 66, 1654351393834], [131, 67, 1654351393844], [131, 68, 1654351393851], [131, 69, 1654351393874], [130, 69, 1654351393883], [129, 70, 1654351393890], [128, 71, 1654351393899], [124, 74, 1654351393907], [123, 75, 1654351393915], [121, 77, 1654351393923], [119, 79, 1654351393931], [118, 81, 1654351393939], [116, 84, 1654351393948], [115, 86, 1654351393955], [114, 88, 1654351393967], [114, 89, 1654351393971], [113, 92, 1654351393982], [112, 94, 1654351393988], [112, 97, 1654351393998], [112, 98, 1654351394006], [112, 100, 1654351394011], [112, 101, 1654351394020], [112, 102, 1654351394032], [112, 103, 1654351394083], [112, 104, 1654351394091], [111, 104, 1654351394100], [111, 105, 1654351394115], [110, 106, 1654351394141], [110, 107, 1654351394158], [110, 108, 1654351394174], [111, 109, 1654351394190], [112, 109, 1654351394202], [113, 109, 1654351394210], [114, 109, 1654351394215], [115, 109, 1654351394222], [117, 109, 1654351394231], [118, 109, 1654351394242], [119, 109, 1654351394247], [121, 109, 1654351394256], [124, 109, 1654351394263], [127, 109, 1654351394273], [130, 109, 1654351394279], [134, 109, 1654351394289], [139, 109, 1654351394293], [143, 109, 1654351394306], [146, 109, 1654351394313], [149, 109, 1654351394322], [152, 109, 1654351394326], [153, 109, 1654351394338], [157, 109, 1654351394342], [158, 109, 1654351394350], [160, 109, 1654351394356], [162, 109, 1654351394365], [165, 109, 1654351394373], [168, 109, 1654351394379], [171, 109, 1654351394388], [178, 109, 1654351394396], [182, 109, 1654351394405], [186, 109, 1654351394412], [191, 109, 1654351394421], [195, 109, 1654351394428], [199, 109, 1654351394440], [201, 109, 1654351394447], [207, 109, 1654351394460], [209, 109, 1654351394465], [212, 109, 1654351394474], [214, 109, 1654351394481], [217, 109, 1654351394488], [222, 109, 1654351394497], [227, 109, 1654351394507], [232, 109, 1654351394513], [236, 109, 1654351394523], [243, 109, 1654351394528], [249, 109, 1654351394540], [254, 109, 1654351394545], [257, 109, 1654351394553], [264, 109, 1654351394559], [269, 109, 1654351394567], [272, 109, 1654351394575], [276, 109, 1654351394582], [280, 109, 1654351394589], [283, 109, 1654351394598], [288, 109, 1654351394605], [292, 109, 1654351394614], [295, 109, 1654351394621], [297, 109, 1654351394629], [301, 109, 1654351394637], [305, 109, 1654351394645], [308, 109, 1654351394654], [310, 109, 1654351394661], [314, 109, 1654351394669], [317, 109, 1654351394681], [320, 109, 1654351394685], [323, 109, 1654351394695], [326, 109, 1654351394701], [328, 109, 1654351394711], [331, 109, 1654351394717], [332, 109, 1654351394727], [335, 109, 1654351394735], [336, 109, 1654351394744], [339, 109, 1654351394751], [341, 109, 1654351394767], [343, 109, 1654351394775], [344, 109, 1654351394784], [345, 109, 1654351394791], [346, 109, 1654351394810], [348, 109, 1654351394821], [349, 109, 1654351394829], [351, 109, 1654351394835], [355, 109, 1654351394844], [358, 109, 1654351394857], [361, 109, 1654351394863], [364, 109, 1654351394870], [366, 109, 1654351394876], [371, 109, 1654351394884], [376, 109, 1654351394892], [380, 109, 1654351394901], [384, 109, 1654351394907], [386, 109, 1654351394915], [387, 110, 1654351394924], [388, 110, 1654351394932], [386, 110, 1654351395029], [383, 111, 1654351395038], [380, 112, 1654351395048], [375, 113, 1654351395055], [367, 114, 1654351395063], [357, 116, 1654351395072], [347, 117, 1654351395082], [342, 117, 1654351395087], [325, 119, 1654351395093], [320, 120, 1654351395102], [312, 121, 1654351395111], [305, 122, 1654351395117], [300, 122, 1654351395125], [299, 122, 1654351395135], [297, 122, 1654351395142], [296, 122, 1654351395150], [295, 121, 1654351395159], [294, 121, 1654351395167], [293, 121, 1654351395172], [293, 120, 1654351395178], [291, 120, 1654351395188], [290, 120, 1654351395196], [288, 119, 1654351395204], [285, 119, 1654351395213], [283, 119, 1654351395222], [280, 119, 1654351395233], [276, 119, 1654351395241], [273, 119, 1654351395248], [269, 119, 1654351395258], [266, 119, 1654351395263], [265, 119, 1654351395270], [263, 119, 1654351395275], [262, 119, 1654351395284], [261, 119, 1654351395305], [260, 119, 1654351395361], [259, 119, 1654351395392], [259, 121, 1654351395422], [258, 123, 1654351395432], [258, 126, 1654351395446], [257, 131, 1654351395456], [257, 134, 1654351395462], [256, 137, 1654351395471], [256, 140, 1654351395478], [255, 144, 1654351395485], [255, 147, 1654351395493], [255, 152, 1654351395499], [254, 158, 1654351395504], [253, 162, 1654351395516], [253, 164, 1654351395523], [253, 167, 1654351395532], [252, 171, 1654351395540], [252, 174, 1654351395547], [252, 178, 1654351395553], [252, 181, 1654351395556], [252, 184, 1654351395565], [252, 186, 1654351395579], [252, 190, 1654351395585], [252, 192, 1654351395595], [252, 195, 1654351395602], [252, 198, 1654351395611], [252, 200, 1654351395622], [252, 204, 1654351395629], [252, 207, 1654351395635], [252, 211, 1654351395649], [252, 214, 1654351395663], [252, 218, 1654351395672], [252, 221, 1654351395679], [252, 224, 1654351395684], [252, 226, 1654351395689], [252, 229, 1654351395695], [252, 232, 1654351395703], [252, 235, 1654351395709], [252, 236, 1654351395719], [252, 239, 1654351395725], [251, 241, 1654351395735], [251, 243, 1654351395742], [251, 245, 1654351395750], [251, 247, 1654351395758], [250, 249, 1654351395766], [250, 251, 1654351395778], [250, 252, 1654351395793], [250, 253, 1654351395801], [250, 254, 1654351395807], [250, 255, 1654351395816], [250, 256, 1654351395826], [250, 257, 1654351395842], [248, 257, 1654351396003], [244, 257, 1654351396014], [242, 257, 1654351396026], [235, 259, 1654351396034], [228, 259, 1654351396041], [222, 259, 1654351396047], [203, 261, 1654351396060], [190, 261, 1654351396086], [157, 263, 1654351396092], [148, 264, 1654351396102], [141, 265, 1654351396112], [136, 265, 1654351396120], [128, 267, 1654351396127], [124, 267, 1654351396134], [123, 268, 1654351396144], [121, 268, 1654351396151], [119, 269, 1654351396157], [118, 269, 1654351396171], [117, 270, 1654351396182], [116, 270, 1654351396199], [117, 270, 1654351396227], [119, 270, 1654351396234], [122, 270, 1654351396242], [124, 270, 1654351396251], [128, 270, 1654351396258], [135, 270, 1654351396267], [140, 270, 1654351396274], [148, 270, 1654351396282], [153, 270, 1654351396290], [165, 270, 1654351396298], [173, 270, 1654351396306], [185, 270, 1654351396313], [206, 270, 1654351396322], [218, 270, 1654351396330], [228, 270, 1654351396338], [247, 270, 1654351396347], [258, 270, 1654351396354], [267, 270, 1654351396363], [275, 270, 1654351396371], [280, 270, 1654351396379], [288, 270, 1654351396387], [293, 270, 1654351396397], [298, 270, 1654351396402], [302, 270, 1654351396412], [304, 270, 1654351396417], [307, 270, 1654351396428], [309, 270, 1654351396436], [311, 270, 1654351396444], [312, 270, 1654351396476], [313, 270, 1654351396492], [314, 270, 1654351396499], [315, 270, 1654351396509], [317, 270, 1654351396517], [318, 270, 1654351396523], [319, 270, 1654351396533], [321, 271, 1654351396539], [322, 271, 1654351396548], [323, 271, 1654351396557], [324, 272, 1654351396563], [325, 272, 1654351396572], [326, 272, 1654351396580], [327, 272, 1654351396588], [329, 273, 1654351396597], [331, 273, 1654351396603], [332, 274, 1654351396612], [334, 274, 1654351396619], [336, 274, 1654351396630], [338, 275, 1654351396636], [339, 275, 1654351396644], [340, 276, 1654351396652], [341, 276, 1654351396659], [342, 278, 1654351396669], [343, 278, 1654351396678], [345, 278, 1654351396684], [345, 279, 1654351396693], [346, 279, 1654351396704], [346, 280, 1654351396710], [346, 281, 1654351396725], [346, 282, 1654351396735], [346, 284, 1654351396742], [346, 285, 1654351396749], [346, 290, 1654351396758], [346, 292, 1654351396765], [346, 296, 1654351396775], [346, 299, 1654351396782], [346, 303, 1654351396789], [346, 306, 1654351396798], [346, 310, 1654351396806], [346, 318, 1654351396815], [346, 324, 1654351396822], [346, 328, 1654351396830], [346, 335, 1654351396838], [346, 340, 1654351396846], [346, 347, 1654351396859], [346, 356, 1654351396876], [346, 361, 1654351396886], [346, 367, 1654351396894], [346, 373, 1654351396906], [346, 376, 1654351396918], [346, 378, 1654351396926], [346, 383, 1654351396937], [346, 384, 1654351396950], [346, 385, 1654351396961], [346, 386, 1654351396974], [345, 386, 1654351397025], [344, 386, 1654351397041], [342, 386, 1654351397052], [341, 386, 1654351397066], [338, 386, 1654351397078], [325, 386, 1654351397089], [318, 386, 1654351397099], [313, 386, 1654351397105], [304, 386, 1654351397110], [291, 386, 1654351397116], [281, 386, 1654351397122], [260, 386, 1654351397129], [251, 386, 1654351397137], [234, 388, 1654351397147], [227, 388, 1654351397154], [210, 389, 1654351397167], [203, 389, 1654351397174], [188, 389, 1654351397180], [178, 389, 1654351397187], [169, 389, 1654351397196], [164, 389, 1654351397204], [152, 389, 1654351397210], [145, 389, 1654351397220], [138, 389, 1654351397227], [136, 389, 1654351397234], [130, 390, 1654351397245], [127, 390, 1654351397250], [123, 390, 1654351397259], [122, 390, 1654351397266], [119, 391, 1654351397275], [116, 391, 1654351397281], [114, 391, 1654351397292], [112, 391, 1654351397300], [111, 391, 1654351397385], [111, 392, 1654351397522], [112, 392, 1654351397546], [116, 393, 1654351397555], [121, 394, 1654351397564], [129, 395, 1654351397574], [134, 395, 1654351397587], [143, 396, 1654351397593], [150, 396, 1654351397599], [156, 396, 1654351397604], [164, 396, 1654351397614], [174, 396, 1654351397620], [180, 396, 1654351397629], [188, 396, 1654351397641], [195, 396, 1654351397652], [202, 396, 1654351397662], [212, 395, 1654351397676], [216, 395, 1654351397687], [218, 394, 1654351397700], [221, 394, 1654351397713], [227, 393, 1654351397734], [231, 393, 1654351397745], [232, 393, 1654351397755], [233, 393, 1654351397771], [234, 393, 1654351397779], [235, 393, 1654351397789], [236, 393, 1654351397830], [237, 394, 1654351397920], [237, 395, 1654351397934], [238, 397, 1654351397948], [239, 402, 1654351397962], [240, 405, 1654351397972], [241, 410, 1654351397981], [241, 412, 1654351397993], [242, 416, 1654351398002], [243, 418, 1654351398012], [244, 424, 1654351398024], [244, 426, 1654351398032], [244, 431, 1654351398042], [244, 434, 1654351398051], [243, 439, 1654351398060], [242, 444, 1654351398074], [242, 445, 1654351398086], [242, 447, 1654351398096], [241, 449, 1654351398106], [240, 453, 1654351398118], [239, 455, 1654351398127], [239, 456, 1654351398132], [239, 458, 1654351398138], [238, 459, 1654351398146], [238, 460, 1654351398154], [238, 463, 1654351398161], [238, 465, 1654351398169], [237, 467, 1654351398180], [237, 469, 1654351398189], [237, 471, 1654351398196], [237, 473, 1654351398205], [237, 474, 1654351398211], [237, 475, 1654351398219], [237, 476, 1654351398232], [237, 477, 1654351398245], [237, 478, 1654351398251], [237, 480, 1654351398260], [238, 481, 1654351398269], [239, 482, 1654351398278], [239, 483, 1654351398284], [239, 484, 1654351398292], [239, 485, 1654351398304], [240, 485, 1654351398328], [240, 486, 1654351398341], [240, 487, 1654351398353], [240, 488, 1654351398364], [241, 489, 1654351398376], [242, 489, 1654351398485], [242, 488, 1654351398496], [242, 482, 1654351398506], [241, 475, 1654351398516], [241, 468, 1654351398526], [238, 459, 1654351398537], [233, 438, 1654351398547], [232, 430, 1654351398557], [228, 418, 1654351398567], [217, 389, 1654351398576], [212, 377, 1654351398585], [201, 352, 1654351398599], [163, 275, 1654351398618], [149, 253, 1654351398627], [142, 243, 1654351398632], [130, 227, 1654351398637], [127, 221, 1654351398642], [123, 216, 1654351398650], [120, 210, 1654351398657], [118, 207, 1654351398666], [116, 201, 1654351398673], [114, 196, 1654351398683], [112, 193, 1654351398691], [110, 187, 1654351398699], [109, 179, 1654351398711], [105, 168, 1654351398717], [103, 160, 1654351398724], [99, 147, 1654351398732], [98, 141, 1654351398740], [95, 134, 1654351398756], [95, 131, 1654351398770], [94, 127, 1654351398783], [94, 125, 1654351398794], [94, 122, 1654351398807], [94, 119, 1654351398818], [94, 118, 1654351398828], [94, 117, 1654351398838], [94, 118, 1654351398878], [94, 120, 1654351398893], [94, 122, 1654351398904], [94, 124, 1654351398914], [94, 132, 1654351398924], [94, 137, 1654351398936], [94, 141, 1654351398949], [94, 162, 1654351398962], [94, 180, 1654351398971], [94, 188, 1654351398982], [94, 199, 1654351398994], [94, 215, 1654351399008], [94, 224, 1654351399016], [94, 236, 1654351399022], [94, 242, 1654351399026], [94, 249, 1654351399033], [95, 256, 1654351399039], [96, 266, 1654351399045], [97, 271, 1654351399063], [99, 282, 1654351399073], [99, 287, 1654351399082], [99, 291, 1654351399093], [99, 302, 1654351399106], [99, 307, 1654351399116], [99, 318, 1654351399127], [99, 322, 1654351399140], [99, 331, 1654351399152], [99, 338, 1654351399163], [100, 348, 1654351399174], [100, 354, 1654351399188], [100, 363, 1654351399200], [100, 369, 1654351399208], [100, 372, 1654351399214], [100, 376, 1654351399218], [100, 384, 1654351399224], [100, 388, 1654351399231], [99, 394, 1654351399238], [98, 398, 1654351399246], [98, 403, 1654351399264], [97, 408, 1654351399273], [97, 413, 1654351399284], [96, 418, 1654351399295], [96, 425, 1654351399310], [93, 435, 1654351399320], [93, 436, 1654351399331], [93, 441, 1654351399343], [93, 453, 1654351399355], [93, 463, 1654351399370], [93, 468, 1654351399380], [93, 479, 1654351399392], [93, 483, 1654351399403], [92, 486, 1654351399413], [92, 490, 1654351399426], [92, 496, 1654351399441], [92, 497, 1654351399457], [92, 498, 1654351399469], [94, 499, 1654351399530], [95, 499, 1654351399545], [98, 500, 1654351399560], [101, 501, 1654351399576], [104, 501, 1654351399589], [107, 501, 1654351399601], [116, 501, 1654351399617], [129, 501, 1654351399630], [133, 501, 1654351399640], [142, 501, 1654351399661], [147, 501, 1654351399681], [154, 501, 1654351399691], [159, 501, 1654351399699], [162, 501, 1654351399708], [167, 501, 1654351399717], [172, 501, 1654351399726], [178, 501, 1654351399732], [180, 501, 1654351399741], [182, 501, 1654351399747], [184, 501, 1654351399756], [186, 501, 1654351399765], [188, 501, 1654351399775], [189, 501, 1654351399781], [190, 501, 1654351399791], [194, 501, 1654351399796], [195, 501, 1654351399807], [198, 501, 1654351399813], [201, 501, 1654351399820], [204, 501, 1654351399827], [208, 501, 1654351399835], [214, 501, 1654351399845], [217, 501, 1654351399854], [219, 501, 1654351399861], [224, 501, 1654351399872], [227, 501, 1654351399878], [230, 501, 1654351399887], [232, 501, 1654351399894], [236, 501, 1654351399902], [239, 501, 1654351399913], [242, 501, 1654351399917], [246, 501, 1654351399925], [250, 501, 1654351399934], [256, 501, 1654351399941], [263, 501, 1654351399952], [267, 501, 1654351399958], [271, 501, 1654351399965], [275, 501, 1654351399974], [278, 500, 1654351399982], [282, 500, 1654351399993], [285, 500, 1654351399998], [287, 500, 1654351400007], [290, 500, 1654351400014], [292, 500, 1654351400022], [293, 500, 1654351400032], [295, 500, 1654351400038], [297, 500, 1654351400046], [299, 500, 1654351400054], [302, 500, 1654351400062], [304, 500, 1654351400072], [306, 500, 1654351400078], [308, 500, 1654351400086], [309, 500, 1654351400094], [311, 500, 1654351400102], [313, 500, 1654351400112], [315, 500, 1654351400121], [318, 500, 1654351400128], [322, 500, 1654351400136], [327, 500, 1654351400144], [332, 500, 1654351400152], [337, 500, 1654351400159], [340, 501, 1654351400166], [344, 501, 1654351400176], [351, 501, 1654351400183], [354, 501, 1654351400191], [356, 501, 1654351400201], [359, 501, 1654351400207], [361, 502, 1654351400218], [366, 502, 1654351400223], [371, 503, 1654351400233], [375, 503, 1654351400239], [378, 504, 1654351400246], [381, 504, 1654351400255], [382, 505, 1654351400261], [383, 505, 1654351400271], [384, 505, 1654351400279], [384, 503, 1654351400598], [384, 502, 1654351400611], [384, 500, 1654351400629], [384, 499, 1654351400645], [383, 499, 1654351400698], [384, 499, 1654351401547], [385, 499, 1654351401616], [386, 499, 1654351401648], [387, 499, 1654351401658], [390, 499, 1654351401672], [394, 499, 1654351401685], [407, 503, 1654351401701], [421, 508, 1654351401719], [440, 510, 1654351401740], [457, 511, 1654351401757], [465, 511, 1654351401775], [475, 509, 1654351401785], [480, 509, 1654351401792], [489, 509, 1654351401800], [499, 509, 1654351401807], [509, 509, 1654351401812], [521, 509, 1654351401821], [529, 509, 1654351401827], [542, 509, 1654351401835], [554, 509, 1654351401844], [564, 509, 1654351401852], [574, 508, 1654351401861], [583, 507, 1654351401869], [593, 506, 1654351401878], [600, 506, 1654351401887], [610, 506, 1654351401893], [616, 506, 1654351401901], [623, 506, 1654351401909], [628, 506, 1654351401918], [633, 506, 1654351401925], [636, 506, 1654351401933], [639, 506, 1654351401943], [640, 506, 1654351401949], [641, 506, 1654351402027], [642, 506, 1654351402034], [643, 506, 1654351402059], [643, 505, 1654351402190], [642, 503, 1654351402212], [641, 502, 1654351402225], [640, 500, 1654351402244], [639, 499, 1654351402260], [638, 498, 1654351402272], [636, 496, 1654351402293], [635, 495, 1654351402308], [633, 494, 1654351402326], [631, 492, 1654351402338], [630, 490, 1654351402353], [626, 486, 1654351402368], [625, 484, 1654351402382], [622, 483, 1654351402398], [621, 480, 1654351402412], [619, 479, 1654351402426], [618, 477, 1654351402441], [617, 476, 1654351402456], [616, 475, 1654351402469], [614, 472, 1654351402479], [613, 471, 1654351402486], [613, 470, 1654351402492], [612, 469, 1654351402497], [612, 468, 1654351402504], [611, 467, 1654351402524], [610, 466, 1654351402540], [609, 463, 1654351402558], [607, 461, 1654351402572], [605, 460, 1654351402592], [603, 455, 1654351402606], [602, 453, 1654351402621], [600, 449, 1654351402640], [598, 444, 1654351402660], [597, 441, 1654351402675], [595, 438, 1654351402695], [593, 432, 1654351402717], [591, 426, 1654351402725], [588, 420, 1654351402738], [588, 418, 1654351402746], [586, 415, 1654351402754], [584, 411, 1654351402761], [583, 409, 1654351402768], [583, 407, 1654351402779], [582, 405, 1654351402786], [582, 404, 1654351402794], [581, 402, 1654351402802], [580, 400, 1654351402809], [578, 395, 1654351402829], [577, 393, 1654351402847], [575, 386, 1654351402861], [572, 381, 1654351402876], [571, 378, 1654351402890], [570, 373, 1654351402905], [569, 371, 1654351402915], [568, 368, 1654351402921], [566, 362, 1654351402938], [564, 359, 1654351402943], [563, 356, 1654351402947], [562, 352, 1654351402955], [560, 350, 1654351402961], [560, 349, 1654351402970], [559, 347, 1654351402980], [558, 346, 1654351402987], [558, 344, 1654351402994], [557, 344, 1654351403004], [557, 342, 1654351403011], [556, 341, 1654351403022], [556, 340, 1654351403028], [555, 339, 1654351403035], [555, 337, 1654351403044], [553, 335, 1654351403050], [553, 333, 1654351403060], [552, 332, 1654351403068], [551, 330, 1654351403074], [550, 327, 1654351403084], [550, 326, 1654351403090], [549, 325, 1654351403100], [549, 323, 1654351403109], [548, 322, 1654351403115], [548, 321, 1654351403124], [547, 320, 1654351403131], [546, 318, 1654351403140], [545, 316, 1654351403147], [545, 314, 1654351403154], [544, 311, 1654351403166], [544, 309, 1654351403172], [543, 307, 1654351403180], [542, 305, 1654351403188], [542, 303, 1654351403195], [540, 301, 1654351403204], [540, 299, 1654351403211], [539, 297, 1654351403220], [539, 295, 1654351403228], [538, 293, 1654351403236], [537, 291, 1654351403246], [536, 287, 1654351403254], [535, 282, 1654351403260], [534, 279, 1654351403270], [533, 275, 1654351403276], [533, 274, 1654351403287], [531, 269, 1654351403294], [530, 266, 1654351403301], [530, 263, 1654351403311], [529, 260, 1654351403318], [529, 258, 1654351403327], [529, 257, 1654351403334], [528, 254, 1654351403341], [528, 252, 1654351403350], [527, 249, 1654351403357], [527, 247, 1654351403367], [526, 245, 1654351403375], [526, 243, 1654351403383], [525, 241, 1654351403393], [524, 238, 1654351403398], [524, 237, 1654351403407], [524, 234, 1654351403414], [524, 230, 1654351403421], [523, 228, 1654351403430], [523, 224, 1654351403437], [523, 222, 1654351403446], [523, 219, 1654351403454], [523, 216, 1654351403463], [523, 215, 1654351403470], [523, 213, 1654351403478], [523, 210, 1654351403486], [523, 209, 1654351403494], [523, 207, 1654351403502], [523, 206, 1654351403510], [523, 204, 1654351403517], [523, 201, 1654351403527], [523, 198, 1654351403534], [523, 196, 1654351403540], [523, 193, 1654351403550], [523, 191, 1654351403558], [523, 190, 1654351403567], [523, 188, 1654351403576], [524, 186, 1654351403583], [524, 184, 1654351403593], [524, 182, 1654351403600], [525, 180, 1654351403608], [526, 178, 1654351403616], [526, 176, 1654351403623], [526, 174, 1654351403633], [526, 173, 1654351403641], [527, 172, 1654351403650], [527, 170, 1654351403659], [528, 169, 1654351403665], [528, 168, 1654351403672], [528, 167, 1654351403680], [529, 166, 1654351403688], [529, 165, 1654351403697], [530, 163, 1654351403706], [531, 162, 1654351403713], [532, 160, 1654351403721], [534, 159, 1654351403729], [535, 157, 1654351403737], [535, 156, 1654351403745], [536, 156, 1654351403755], [538, 154, 1654351403760], [539, 152, 1654351403767], [540, 151, 1654351403777], [541, 150, 1654351403783], [542, 149, 1654351403806], [543, 147, 1654351403828], [546, 144, 1654351403845], [548, 142, 1654351403862], [550, 140, 1654351403881], [552, 139, 1654351403899], [556, 137, 1654351403916], [559, 135, 1654351403930], [560, 134, 1654351403938], [561, 133, 1654351403946], [562, 133, 1654351403952], [564, 132, 1654351403958], [566, 132, 1654351403964], [568, 131, 1654351403972], [569, 130, 1654351403980], [572, 130, 1654351403990], [573, 129, 1654351403996], [575, 129, 1654351404002], [577, 129, 1654351404011], [578, 129, 1654351404023], [579, 128, 1654351404032], [580, 128, 1654351404041], [581, 128, 1654351404049], [583, 128, 1654351404055], [585, 127, 1654351404061], [586, 127, 1654351404069], [587, 127, 1654351404075], [588, 127, 1654351404082], [589, 127, 1654351404091], [590, 127, 1654351404104], [592, 127, 1654351404110], [594, 127, 1654351404116], [596, 127, 1654351404123], [599, 127, 1654351404130], [602, 127, 1654351404141], [605, 127, 1654351404148], [609, 127, 1654351404155], [611, 127, 1654351404164], [613, 127, 1654351404171], [616, 128, 1654351404192], [617, 128, 1654351404209], [619, 128, 1654351404231], [622, 128, 1654351404250], [626, 128, 1654351404268], [629, 128, 1654351404286], [629, 129, 1654351404299], [630, 129, 1654351404309], [631, 129, 1654351404333], [632, 131, 1654351404356], [635, 134, 1654351404373], [637, 137, 1654351404393], [639, 139, 1654351404410], [641, 142, 1654351404430], [642, 144, 1654351404451], [644, 147, 1654351404467], [647, 152, 1654351404488], [648, 155, 1654351404513], [650, 160, 1654351404532], [651, 163, 1654351404549], [652, 166, 1654351404567], [652, 167, 1654351404589], [653, 169, 1654351404607], [654, 170, 1654351404615], [655, 174, 1654351404627], [656, 176, 1654351404635], [657, 177, 1654351404641], [658, 180, 1654351404654], [658, 181, 1654351404665], [659, 182, 1654351404671], [659, 184, 1654351404679], [660, 186, 1654351404696], [661, 187, 1654351404705], [661, 188, 1654351404713], [662, 188, 1654351404720], [662, 189, 1654351404728], [663, 190, 1654351404737], [663, 191, 1654351404745], [663, 192, 1654351404756], [663, 194, 1654351404762], [664, 195, 1654351404769], [664, 196, 1654351404782], [665, 197, 1654351404807], [665, 198, 1654351404823], [665, 199, 1654351404831], [665, 200, 1654351404861], [665, 201, 1654351404878], [665, 202, 1654351404900], [666, 204, 1654351404921], [667, 207, 1654351404941], [668, 208, 1654351404959], [668, 211, 1654351404983], [669, 213, 1654351405002], [669, 214, 1654351405019], [670, 215, 1654351405039], [672, 219, 1654351405063], [674, 221, 1654351405081], [675, 223, 1654351405099], [677, 228, 1654351405115], [678, 231, 1654351405129], [679, 233, 1654351405140], [680, 235, 1654351405150], [681, 237, 1654351405171], [681, 238, 1654351405181], [682, 239, 1654351405191], [682, 241, 1654351405202], [684, 245, 1654351405214], [685, 248, 1654351405230], [686, 251, 1654351405246], [687, 253, 1654351405255], [687, 254, 1654351405263], [687, 255, 1654351405274], [688, 256, 1654351405285], [688, 258, 1654351405293], [689, 259, 1654351405307], [689, 260, 1654351405316], [690, 261, 1654351405324], [690, 262, 1654351405333], [690, 263, 1654351405342], [691, 264, 1654351405362], [691, 265, 1654351405370], [692, 264, 1654351405491], [694, 262, 1654351405500], [695, 259, 1654351405509], [696, 257, 1654351405517], [700, 252, 1654351405539], [702, 249, 1654351405563], [705, 242, 1654351405583], [707, 238, 1654351405602], [708, 233, 1654351405624], [712, 226, 1654351405644], [715, 219, 1654351405666], [717, 215, 1654351405686], [718, 210, 1654351405707], [719, 207, 1654351405727], [722, 202, 1654351405740], [722, 201, 1654351405747], [723, 199, 1654351405754], [724, 196, 1654351405760], [725, 195, 1654351405769], [725, 194, 1654351405775], [726, 192, 1654351405784], [726, 191, 1654351405790], [727, 190, 1654351405799], [728, 189, 1654351405808], [728, 187, 1654351405814], [729, 185, 1654351405822], [731, 183, 1654351405831], [731, 181, 1654351405839], [732, 180, 1654351405849], [733, 178, 1654351405856], [735, 177, 1654351405865], [735, 175, 1654351405874], [736, 174, 1654351405882], [737, 173, 1654351405890], [738, 171, 1654351405896], [739, 170, 1654351405905], [739, 169, 1654351405913], [740, 167, 1654351405921], [740, 166, 1654351405929], [741, 165, 1654351405943], [742, 164, 1654351405957], [743, 163, 1654351405963], [743, 162, 1654351405969], [743, 161, 1654351405976], [744, 161, 1654351405985], [744, 160, 1654351405996], [745, 160, 1654351406002], [745, 159, 1654351406010], [745, 158, 1654351406031], [746, 158, 1654351406041], [747, 157, 1654351406054], [748, 157, 1654351406062], [748, 156, 1654351406074], [749, 156, 1654351406082], [750, 155, 1654351406094], [751, 155, 1654351406107], [751, 154, 1654351406113], [752, 154, 1654351406124], [753, 153, 1654351406130], [754, 153, 1654351406141], [756, 152, 1654351406152], [758, 152, 1654351406158], [759, 150, 1654351406164], [761, 150, 1654351406173], [762, 149, 1654351406185], [763, 149, 1654351406196], [764, 148, 1654351406203], [765, 148, 1654351406216], [766, 148, 1654351406225], [767, 147, 1654351406241], [768, 147, 1654351406249], [769, 147, 1654351406280], [770, 147, 1654351406289], [771, 147, 1654351406305], [772, 147, 1654351406316], [773, 147, 1654351406323], [774, 147, 1654351406332], [777, 147, 1654351406339], [779, 147, 1654351406347], [782, 147, 1654351406356], [783, 147, 1654351406362], [788, 147, 1654351406371], [789, 147, 1654351406379], [791, 147, 1654351406387], [792, 147, 1654351406400], [794, 147, 1654351406410], [795, 149, 1654351406419], [798, 149, 1654351406427], [800, 150, 1654351406436], [803, 152, 1654351406456], [804, 153, 1654351406464], [805, 154, 1654351406471], [806, 155, 1654351406478], [808, 156, 1654351406487], [809, 157, 1654351406493], [810, 158, 1654351406503], [812, 159, 1654351406510], [813, 161, 1654351406519], [815, 163, 1654351406525], [816, 164, 1654351406534], [816, 166, 1654351406543], [818, 167, 1654351406549], [819, 169, 1654351406557], [819, 171, 1654351406564], [820, 173, 1654351406575], [821, 174, 1654351406582], [822, 176, 1654351406590], [822, 177, 1654351406599], [822, 178, 1654351406607], [823, 179, 1654351406614], [823, 182, 1654351406623], [823, 184, 1654351406630], [824, 187, 1654351406637], [825, 189, 1654351406647], [825, 192, 1654351406653], [825, 195, 1654351406662], [827, 198, 1654351406668], [827, 200, 1654351406680], [828, 203, 1654351406688], [828, 205, 1654351406696], [829, 207, 1654351406704], [829, 209, 1654351406714], [829, 210, 1654351406720], [829, 211, 1654351406729], [829, 213, 1654351406735], [829, 215, 1654351406743], [829, 218, 1654351406751], [829, 221, 1654351406760], [827, 226, 1654351406770], [827, 228, 1654351406777], [825, 236, 1654351406784], [824, 241, 1654351406796], [822, 244, 1654351406803], [821, 247, 1654351406818], [820, 251, 1654351406831], [820, 252, 1654351406838], [820, 254, 1654351406845], [818, 256, 1654351406854], [817, 257, 1654351406864], [816, 261, 1654351406873], [814, 264, 1654351406880], [813, 267, 1654351406889], [811, 271, 1654351406896], [809, 274, 1654351406910], [807, 278, 1654351406918], [806, 281, 1654351406924], [803, 284, 1654351406931], [802, 286, 1654351406937], [802, 288, 1654351406945], [800, 289, 1654351406953], [799, 291, 1654351406962], [798, 294, 1654351406972], [797, 296, 1654351406980], [795, 300, 1654351406986], [793, 303, 1654351406999], [791, 307, 1654351407009], [789, 310, 1654351407015], [787, 314, 1654351407024], [785, 318, 1654351407030], [782, 322, 1654351407036], [779, 326, 1654351407045], [777, 331, 1654351407055], [774, 335, 1654351407063], [772, 339, 1654351407069], [769, 343, 1654351407078], [768, 347, 1654351407088], [767, 348, 1654351407099], [763, 355, 1654351407107], [760, 363, 1654351407122], [758, 366, 1654351407134], [755, 371, 1654351407145], [750, 379, 1654351407155], [749, 381, 1654351407165], [748, 385, 1654351407175], [746, 387, 1654351407185], [743, 396, 1654351407196], [742, 399, 1654351407205], [741, 403, 1654351407214], [740, 406, 1654351407223], [739, 411, 1654351407229], [738, 414, 1654351407235], [736, 420, 1654351407248], [735, 423, 1654351407261], [734, 426, 1654351407270], [732, 428, 1654351407280], [732, 429, 1654351407289], [731, 431, 1654351407297], [731, 432, 1654351407308], [729, 434, 1654351407321], [729, 435, 1654351407329], [728, 436, 1654351407340], [726, 439, 1654351407349], [725, 440, 1654351407358], [723, 442, 1654351407370], [721, 445, 1654351407383], [718, 447, 1654351407402], [718, 448, 1654351407414], [717, 450, 1654351407423], [715, 451, 1654351407431], [714, 452, 1654351407440], [713, 453, 1654351407448], [711, 454, 1654351407458], [710, 455, 1654351407465], [708, 456, 1654351407475], [707, 457, 1654351407481], [706, 458, 1654351407489], [705, 459, 1654351407497], [705, 460, 1654351407504], [704, 461, 1654351407512], [703, 461, 1654351407520], [702, 462, 1654351407528], [701, 463, 1654351407535], [700, 464, 1654351407543], [699, 465, 1654351407550], [698, 466, 1654351407559], [697, 467, 1654351407569], [696, 469, 1654351407579], [695, 470, 1654351407589], [693, 471, 1654351407599], [691, 473, 1654351407609], [689, 475, 1654351407620], [688, 477, 1654351407633], [687, 477, 1654351407642], [687, 478, 1654351407652], [686, 480, 1654351407659], [685, 481, 1654351407667], [683, 482, 1654351407675], [683, 483, 1654351407685], [682, 485, 1654351407695], [681, 486, 1654351407706], [680, 487, 1654351407716], [680, 488, 1654351407728], [678, 489, 1654351407736], [678, 490, 1654351407744], [677, 490, 1654351407752], [676, 491, 1654351407760], [676, 492, 1654351407767], [675, 492, 1654351407774], [674, 493, 1654351407786], [673, 494, 1654351407795], [671, 495, 1654351407802], [670, 496, 1654351407811], [669, 497, 1654351407818], [668, 498, 1654351407826], [667, 498, 1654351407836], [666, 499, 1654351407847], [666, 500, 1654351407856], [665, 500, 1654351407863], [664, 500, 1654351407873], [663, 501, 1654351407881], [662, 501, 1654351407888], [662, 502, 1654351407895], [661, 502, 1654351407903], [660, 502, 1654351407913], [659, 502, 1654351407921], [658, 502, 1654351407932], [657, 503, 1654351407944], [656, 503, 1654351407957], [655, 503, 1654351407967], [654, 504, 1654351407982], [653, 504, 1654351408005], [652, 504, 1654351408036], [651, 504, 1654351408052], [651, 505, 1654351408068], [650, 505, 1654351408079], [649, 505, 1654351408125], [648, 505, 1654351408160], [647, 505, 1654351408193], [645, 506, 1654351408216], [644, 506, 1654351408342], [645, 506, 1654351408786], [651, 503, 1654351408810], [671, 492, 1654351408831], [692, 479, 1654351408851], [721, 454, 1654351408863], [738, 439, 1654351408872], [750, 430, 1654351408881], [761, 423, 1654351408889], [770, 417, 1654351408895], [779, 412, 1654351408902], [793, 402, 1654351408909], [802, 394, 1654351408919], [807, 389, 1654351408926], [812, 384, 1654351408934], [820, 373, 1654351408947], [825, 366, 1654351408955], [830, 359, 1654351408963], [836, 352, 1654351408974], [844, 345, 1654351408983], [847, 342, 1654351408990], [851, 338, 1654351408998], [856, 333, 1654351409005], [860, 328, 1654351409013], [862, 326, 1654351409019], [864, 322, 1654351409030], [865, 316, 1654351409038], [866, 313, 1654351409045], [866, 310, 1654351409053], [866, 308, 1654351409062], [867, 305, 1654351409070], [868, 300, 1654351409079], [870, 295, 1654351409086], [871, 292, 1654351409095], [873, 288, 1654351409102], [875, 281, 1654351409109], [878, 275, 1654351409116], [879, 271, 1654351409126], [881, 265, 1654351409137], [882, 263, 1654351409145], [882, 261, 1654351409154], [882, 266, 1654351409188], [882, 272, 1654351409201], [880, 280, 1654351409209], [877, 291, 1654351409216], [874, 298, 1654351409228], [869, 306, 1654351409237], [867, 313, 1654351409244], [865, 318, 1654351409254], [865, 320, 1654351409263], [864, 322, 1654351409274], [865, 319, 1654351409311], [868, 313, 1654351409321], [882, 290, 1654351409335], [889, 277, 1654351409348], [900, 258, 1654351409358], [906, 244, 1654351409367], [912, 232, 1654351409375], [916, 223, 1654351409383], [923, 207, 1654351409390], [930, 195, 1654351409399], [934, 185, 1654351409410], [944, 160, 1654351409418], [948, 142, 1654351409427], [948, 134, 1654351409434], [949, 123, 1654351409443], [950, 117, 1654351409452], [950, 110, 1654351409463], [950, 102, 1654351409475], [950, 100, 1654351409485], [950, 102, 1654351409542], [950, 109, 1654351409555], [948, 114, 1654351409563], [946, 120, 1654351409574], [944, 125, 1654351409582], [940, 134, 1654351409589], [939, 137, 1654351409598], [936, 143, 1654351409609], [935, 153, 1654351409616], [932, 163, 1654351409624], [931, 171, 1654351409633], [930, 178, 1654351409641], [930, 184, 1654351409651], [927, 193, 1654351409658], [923, 212, 1654351409667], [922, 217, 1654351409679], [920, 227, 1654351409689], [917, 237, 1654351409702], [914, 252, 1654351409710], [911, 262, 1654351409718], [911, 267, 1654351409726], [908, 278, 1654351409734], [906, 284, 1654351409746], [905, 293, 1654351409756], [904, 299, 1654351409763], [903, 308, 1654351409771], [901, 321, 1654351409778], [900, 327, 1654351409786], [898, 337, 1654351409795], [896, 349, 1654351409803], [893, 359, 1654351409814], [888, 378, 1654351409824], [886, 387, 1654351409833], [883, 398, 1654351409841], [881, 404, 1654351409850], [880, 409, 1654351409857], [878, 415, 1654351409868], [878, 420, 1654351409875], [877, 424, 1654351409883], [874, 433, 1654351409891], [873, 438, 1654351409899], [871, 444, 1654351409906], [870, 450, 1654351409916], [869, 453, 1654351409924], [869, 458, 1654351409933], [869, 462, 1654351409942], [869, 465, 1654351409950], [869, 466, 1654351409958], [869, 470, 1654351409968], [868, 471, 1654351409979], [868, 474, 1654351409991], [867, 477, 1654351409999], [867, 482, 1654351410007], [865, 486, 1654351410015], [864, 492, 1654351410024], [864, 497, 1654351410032], [862, 503, 1654351410039], [862, 509, 1654351410048], [862, 514, 1654351410056], [862, 518, 1654351410063], [862, 521, 1654351410070], [862, 524, 1654351410079], [862, 526, 1654351410087], [862, 529, 1654351410095], [862, 531, 1654351410104], [862, 533, 1654351410113], [862, 538, 1654351410122], [862, 539, 1654351410132], [861, 541, 1654351410144], [861, 543, 1654351410153], [860, 546, 1654351410160], [860, 549, 1654351410170], [860, 550, 1654351410179], [859, 553, 1654351410188], [859, 554, 1654351410196], [858, 557, 1654351410204], [858, 560, 1654351410212], [857, 563, 1654351410222], [856, 565, 1654351410230], [856, 567, 1654351410239], [856, 569, 1654351410247], [855, 569, 1654351410255], [855, 570, 1654351410262], [854, 570, 1654351410372], [853, 570, 1654351410386], [853, 571, 1654351410399], [853, 572, 1654351410415], [853, 573, 1654351410431], [853, 574, 1654351410442], [853, 575, 1654351410452], [853, 576, 1654351410460], [853, 577, 1654351410472], [854, 573, 1654351410526], [856, 571, 1654351410538], [858, 568, 1654351410547], [859, 563, 1654351410554], [861, 559, 1654351410562], [862, 555, 1654351410574], [863, 549, 1654351410583], [866, 539, 1654351410593], [867, 529, 1654351410601], [869, 514, 1654351410609], [871, 502, 1654351410616], [874, 489, 1654351410625], [878, 479, 1654351410633], [886, 466, 1654351410643], [889, 462, 1654351410654], [893, 453, 1654351410663], [898, 443, 1654351410672], [902, 430, 1654351410680], [902, 425, 1654351410693], [904, 391, 1654351410705], [904, 384, 1654351410714], [905, 373, 1654351410721], [907, 363, 1654351410731], [909, 356, 1654351410739], [910, 351, 1654351410750], [911, 337, 1654351410762], [911, 335, 1654351410770], [913, 328, 1654351410779], [914, 323, 1654351410788], [917, 315, 1654351410798], [918, 311, 1654351410806], [918, 309, 1654351410814], [918, 306, 1654351410824], [919, 300, 1654351410831], [920, 297, 1654351410842], [920, 293, 1654351410852], [921, 284, 1654351410864], [922, 277, 1654351410873], [922, 271, 1654351410884], [923, 268, 1654351410892], [923, 265, 1654351410900], [923, 262, 1654351410909], [925, 266, 1654351410960], [927, 271, 1654351410974], [930, 279, 1654351410983], [931, 282, 1654351410990], [932, 286, 1654351410999], [932, 289, 1654351411008], [933, 291, 1654351411016], [934, 294, 1654351411029], [934, 297, 1654351411037], [936, 300, 1654351411048], [936, 301, 1654351411057], [938, 304, 1654351411068], [939, 305, 1654351411077], [939, 307, 1654351411084], [940, 308, 1654351411093], [940, 310, 1654351411103], [941, 311, 1654351411112], [941, 312, 1654351411121], [941, 313, 1654351411158], [942, 313, 1654351411170], [942, 314, 1654351411186], [944, 310, 1654351411250], [946, 305, 1654351411264], [949, 295, 1654351411272], [953, 286, 1654351411280], [956, 280, 1654351411288], [961, 268, 1654351411295], [966, 259, 1654351411307], [972, 249, 1654351411317], [989, 227, 1654351411326], [993, 222, 1654351411334], [1001, 210, 1654351411344], [1005, 203, 1654351411353], [1009, 196, 1654351411361], [1012, 188, 1654351411370], [1015, 182, 1654351411378], [1018, 176, 1654351411388], [1025, 160, 1654351411396], [1027, 156, 1654351411405], [1030, 151, 1654351411414], [1032, 148, 1654351411426], [1032, 146, 1654351411436], [1032, 145, 1654351411446], [1033, 145, 1654351411455], [1033, 144, 1654351411464], [1033, 143, 1654351411476], [1033, 142, 1654351411490], [1034, 142, 1654351411500], [1034, 141, 1654351411513], [1034, 140, 1654351411544], [1035, 140, 1654351411555], [1036, 139, 1654351411578], [1037, 138, 1654351411591], [1038, 137, 1654351411602], [1039, 136, 1654351411611], [1040, 134, 1654351411618], [1041, 134, 1654351411628], [1041, 133, 1654351411639], [1041, 136, 1654351411678], [1041, 145, 1654351411697], [1040, 152, 1654351411710], [1037, 159, 1654351411722], [1037, 165, 1654351411732], [1033, 173, 1654351411743], [1030, 181, 1654351411752], [1028, 186, 1654351411760], [1026, 188, 1654351411769], [1024, 193, 1654351411777], [1019, 205, 1654351411788], [1018, 209, 1654351411797], [1014, 215, 1654351411806], [1012, 220, 1654351411814], [1010, 224, 1654351411823], [1007, 230, 1654351411832], [1004, 236, 1654351411841], [1002, 240, 1654351411849], [1000, 243, 1654351411857], [999, 247, 1654351411865], [997, 250, 1654351411874], [996, 251, 1654351411883], [994, 253, 1654351411892], [989, 258, 1654351411905], [986, 262, 1654351411913], [984, 265, 1654351411923], [982, 268, 1654351411932], [980, 269, 1654351411940], [977, 275, 1654351411948], [977, 276, 1654351411958], [976, 277, 1654351411966], [976, 278, 1654351412040], [978, 278, 1654351412064], [980, 278, 1654351412076], [984, 278, 1654351412084], [989, 276, 1654351412097], [993, 276, 1654351412111], [999, 275, 1654351412121], [1003, 274, 1654351412132], [1008, 273, 1654351412142], [1013, 273, 1654351412150], [1014, 273, 1654351412160], [1019, 273, 1654351412170], [1023, 273, 1654351412178], [1028, 273, 1654351412187], [1032, 273, 1654351412198], [1035, 273, 1654351412207], [1038, 273, 1654351412215], [1041, 273, 1654351412225], [1046, 273, 1654351412236], [1049, 273, 1654351412243], [1051, 272, 1654351412253], [1053, 272, 1654351412261], [1055, 271, 1654351412271], [1059, 271, 1654351412279], [1061, 271, 1654351412288], [1064, 270, 1654351412297], [1068, 269, 1654351412306], [1070, 269, 1654351412316], [1071, 268, 1654351412325], [1073, 268, 1654351412334], [1074, 268, 1654351412342], [1076, 267, 1654351412350], [1078, 267, 1654351412358], [1079, 267, 1654351412367], [1080, 266, 1654351412376], [1081, 266, 1654351412385], [1082, 266, 1654351412395], [1082, 265, 1654351412421], [1083, 265, 1654351412436], [1083, 264, 1654351412448], [1083, 262, 1654351412460], [1084, 260, 1654351412468], [1085, 257, 1654351412477], [1085, 255, 1654351412485], [1085, 251, 1654351412495], [1085, 249, 1654351412507], [1085, 246, 1654351412515], [1085, 238, 1654351412524], [1085, 235, 1654351412533], [1085, 233, 1654351412541], [1085, 230, 1654351412550], [1085, 228, 1654351412560], [1084, 227, 1654351412570], [1084, 226, 1654351412578], [1084, 225, 1654351412587], [1084, 224, 1654351412628], [1084, 223, 1654351412644], [1083, 223, 1654351412663], [1083, 222, 1654351412674], [1083, 224, 1654351412823], [1083, 226, 1654351412838], [1083, 227, 1654351412850], [1084, 230, 1654351412859], [1084, 232, 1654351412870], [1085, 235, 1654351412879], [1088, 242, 1654351412887], [1089, 246, 1654351412896], [1091, 249, 1654351412905], [1091, 251, 1654351412914], [1092, 253, 1654351412923], [1093, 256, 1654351412933], [1095, 259, 1654351412943], [1097, 265, 1654351412954], [1098, 267, 1654351412964], [1099, 269, 1654351412974], [1099, 270, 1654351412985], [1101, 273, 1654351412994], [1101, 274, 1654351413003], [1102, 276, 1654351413013], [1102, 278, 1654351413024], [1103, 279, 1654351413033], [1103, 280, 1654351413042], [1103, 281, 1654351413053], [1104, 283, 1654351413062], [1104, 284, 1654351413071], [1105, 284, 1654351413080], [1105, 285, 1654351413090], [1106, 286, 1654351413098], [1106, 288, 1654351413108], [1107, 291, 1654351413117], [1107, 292, 1654351413128], [1108, 292, 1654351413136], [1109, 294, 1654351413151], [1109, 295, 1654351413161], [1110, 295, 1654351413295], [1110, 296, 1654351413444], [1108, 300, 1654351413458], [1105, 302, 1654351413475], [1071, 320, 1654351413494], [1051, 329, 1654351413517], [1018, 336, 1654351413535], [1009, 337, 1654351413559], [1003, 338, 1654351413579], [1001, 338, 1654351413601], [995, 338, 1654351413623], [986, 339, 1654351413638], [984, 339, 1654351413650], [980, 339, 1654351413659], [979, 339, 1654351413668], [978, 339, 1654351413678], [978, 340, 1654351413748], [978, 342, 1654351413762], [978, 346, 1654351413771], [978, 349, 1654351413781], [978, 356, 1654351413791], [978, 366, 1654351413800], [978, 372, 1654351413812], [978, 378, 1654351413823], [978, 387, 1654351413832], [979, 410, 1654351413842], [980, 424, 1654351413851], [980, 434, 1654351413860], [980, 444, 1654351413870], [980, 452, 1654351413881], [980, 459, 1654351413893], [978, 471, 1654351413903], [977, 476, 1654351413916], [976, 480, 1654351413925], [976, 489, 1654351413936], [975, 493, 1654351413947], [975, 497, 1654351413956], [974, 501, 1654351413965], [973, 504, 1654351413975], [973, 505, 1654351413984], [973, 506, 1654351413998], [973, 507, 1654351414008], [973, 508, 1654351414018], [973, 509, 1654351414031], [973, 508, 1654351414120], [973, 507, 1654351414144], [973, 506, 1654351414160], [973, 505, 1654351414260], [974, 501, 1654351414296], [979, 479, 1654351414329], [990, 437, 1654351414367], [991, 398, 1654351414407], [990, 382, 1654351414436], [990, 377, 1654351414449], [990, 376, 1654351414461], [989, 375, 1654351414483], [988, 374, 1654351414500], [987, 371, 1654351414523], [986, 370, 1654351414540], [986, 369, 1654351414552], [985, 369, 1654351414565], [985, 368, 1654351414580], [984, 366, 1654351414595], [983, 365, 1654351414605], [983, 363, 1654351414616], [982, 362, 1654351414626], [981, 360, 1654351414637], [981, 359, 1654351414650], [981, 356, 1654351414660], [981, 355, 1654351414673], [981, 353, 1654351414682], [981, 349, 1654351414697], [981, 348, 1654351414710], [981, 347, 1654351414721], [981, 346, 1654351414737], [981, 345, 1654351414752], [981, 344, 1654351414769], [981, 343, 1654351414789], [982, 343, 1654351414937], [983, 342, 1654351414952], [984, 342, 1654351414962], [986, 342, 1654351414973], [989, 342, 1654351414983], [995, 341, 1654351414992], [998, 341, 1654351415003], [1002, 341, 1654351415012], [1006, 341, 1654351415022], [1011, 340, 1654351415036], [1014, 340, 1654351415045], [1018, 340, 1654351415056], [1020, 340, 1654351415069], [1024, 340, 1654351415080], [1025, 340, 1654351415090], [1027, 340, 1654351415100], [1028, 340, 1654351415110], [1029, 340, 1654351415120], [1031, 340, 1654351415131], [1032, 340, 1654351415140], [1033, 340, 1654351415156], [1034, 340, 1654351415171], [1035, 340, 1654351415181], [1036, 340, 1654351415190], [1037, 340, 1654351415201], [1038, 340, 1654351415211], [1040, 340, 1654351415221], [1041, 340, 1654351415231], [1044, 340, 1654351415247], [1046, 340, 1654351415261], [1047, 340, 1654351415270], [1049, 340, 1654351415280], [1050, 340, 1654351415289], [1051, 340, 1654351415298], [1052, 340, 1654351415308], [1053, 340, 1654351415319], [1054, 340, 1654351415328], [1057, 340, 1654351415340], [1068, 341, 1654351415352], [1072, 341, 1654351415362], [1075, 342, 1654351415372], [1077, 342, 1654351415386], [1077, 343, 1654351415397], [1078, 343, 1654351415412], [1079, 343, 1654351415425], [1080, 344, 1654351415437], [1082, 344, 1654351415448], [1083, 344, 1654351415457], [1083, 345, 1654351415507], [1084, 346, 1654351415521], [1085, 349, 1654351415539], [1086, 352, 1654351415554], [1086, 354, 1654351415566], [1086, 359, 1654351415576], [1086, 363, 1654351415588], [1086, 366, 1654351415598], [1086, 374, 1654351415609], [1086, 376, 1654351415620], [1086, 377, 1654351415631], [1087, 379, 1654351415641], [1087, 381, 1654351415652], [1088, 387, 1654351415662], [1088, 389, 1654351415672], [1088, 392, 1654351415682], [1089, 400, 1654351415692], [1089, 406, 1654351415705], [1091, 412, 1654351415719], [1091, 414, 1654351415730], [1092, 418, 1654351415739], [1092, 421, 1654351415751], [1092, 424, 1654351415761], [1092, 426, 1654351415770], [1092, 433, 1654351415780], [1093, 436, 1654351415792], [1093, 442, 1654351415809], [1093, 444, 1654351415820], [1093, 447, 1654351415829], [1093, 449, 1654351415840], [1093, 451, 1654351415850], [1093, 456, 1654351415859], [1093, 460, 1654351415870], [1093, 466, 1654351415880], [1092, 475, 1654351415890], [1092, 479, 1654351415902], [1091, 484, 1654351415913], [1091, 485, 1654351415924], [1091, 486, 1654351415934], [1091, 487, 1654351415943], [1091, 491, 1654351415952], [1090, 493, 1654351415964], [1089, 495, 1654351415975], [1089, 497, 1654351415985], [1089, 500, 1654351415997], [1089, 501, 1654351416008], [1089, 502, 1654351416017], [1088, 503, 1654351416033], [1088, 504, 1654351416046], [1088, 505, 1654351416057], [1088, 506, 1654351416068], [1088, 507, 1654351416080], [1087, 507, 1654351416097], [1087, 508, 1654351416113], [1087, 509, 1654351416129], [1086, 510, 1654351416139], [1086, 511, 1654351416152], [1085, 513, 1654351416163], [1084, 514, 1654351416175], [1083, 516, 1654351416188], [1082, 519, 1654351416205], [1081, 521, 1654351416217], [1080, 523, 1654351416231], [1079, 525, 1654351416242], [1079, 527, 1654351416255], [1079, 528, 1654351416268], [1078, 529, 1654351416279], [1077, 529, 1654351416359], [1076, 529, 1654351416387], [1071, 528, 1654351416411], [1063, 528, 1654351416427], [1055, 526, 1654351416438], [1051, 525, 1654351416449], [1042, 525, 1654351416460], [1038, 525, 1654351416471], [1031, 525, 1654351416484], [1029, 524, 1654351416494], [1027, 524, 1654351416504], [1023, 522, 1654351416513], [1020, 522, 1654351416527], [1019, 521, 1654351416538], [1018, 521, 1654351416549], [1017, 521, 1654351416559], [1015, 521, 1654351416570], [1013, 520, 1654351416581], [1010, 519, 1654351416591], [1009, 518, 1654351416601], [1008, 518, 1654351416612], [1005, 517, 1654351416622], [1003, 516, 1654351416638], [1000, 516, 1654351416653], [998, 515, 1654351416665], [996, 515, 1654351416676], [994, 514, 1654351416686], [993, 513, 1654351416697], [990, 513, 1654351416709], [987, 512, 1654351416724], [986, 512, 1654351416736], [985, 512, 1654351416746], [984, 512, 1654351416762], [983, 511, 1654351416773], [982, 511, 1654351416798], [981, 510, 1654351416822], [980, 510, 1654351416838], [979, 509, 1654351416849], [978, 509, 1654351416872], [977, 509, 1654351416883], [977, 508, 1654351416893], [976, 508, 1654351416902], [975, 508, 1654351416923], [974, 507, 1654351417364], [974, 504, 1654351417414], [974, 492, 1654351417437], [974, 487, 1654351417459], [973, 480, 1654351417472], [973, 478, 1654351417483], [973, 476, 1654351417494], [973, 475, 1654351417509], [973, 473, 1654351417521], [973, 470, 1654351417533], [973, 469, 1654351417545], [973, 467, 1654351417555], [973, 465, 1654351417575], [973, 464, 1654351417591], [973, 463, 1654351417601], [973, 461, 1654351417611], [973, 458, 1654351417621], [973, 457, 1654351417632], [973, 456, 1654351417645], [973, 453, 1654351417659], [973, 451, 1654351417670], [973, 450, 1654351417680], [973, 449, 1654351417690], [973, 446, 1654351417702], [973, 444, 1654351417717], [973, 440, 1654351417732], [973, 436, 1654351417742], [973, 434, 1654351417753], [974, 431, 1654351417765], [974, 429, 1654351417781], [974, 427, 1654351417791], [974, 425, 1654351417801], [974, 422, 1654351417812], [974, 420, 1654351417823], [974, 419, 1654351417833], [974, 417, 1654351417846], [974, 416, 1654351417856], [974, 415, 1654351417868], [974, 414, 1654351417878], [974, 413, 1654351417888], [974, 412, 1654351417897], [974, 411, 1654351417909], [974, 409, 1654351417922], [974, 407, 1654351417935], [974, 406, 1654351417946], [974, 404, 1654351417958], [975, 403, 1654351417969], [975, 402, 1654351417978], [975, 401, 1654351417988], [975, 400, 1654351418000], [975, 398, 1654351418011], [975, 397, 1654351418024], [976, 395, 1654351418037], [976, 391, 1654351418047], [976, 390, 1654351418059], [976, 389, 1654351418070], [976, 386, 1654351418080], [976, 384, 1654351418091], [976, 383, 1654351418102], [976, 380, 1654351418117], [977, 378, 1654351418136], [977, 377, 1654351418147], [977, 376, 1654351418157], [977, 374, 1654351418167], [977, 373, 1654351418177], [978, 368, 1654351418189], [978, 366, 1654351418201], [978, 362, 1654351418212], [978, 360, 1654351418226], [979, 357, 1654351418239], [979, 354, 1654351418252], [979, 353, 1654351418262], [979, 352, 1654351418278], [979, 351, 1654351418288], [979, 350, 1654351418298], [979, 349, 1654351418309], [979, 347, 1654351418322], [979, 345, 1654351418334], [979, 346, 1654351420339], [980, 349, 1654351420356], [980, 352, 1654351420372], [980, 355, 1654351420386], [983, 380, 1654351420399], [986, 431, 1654351420410], [986, 472, 1654351420421], [978, 533, 1654351420432], [966, 566, 1654351420443], [954, 589, 1654351420455], [921, 635, 1654351420467], [899, 658, 1654351420484], [871, 682, 1654351420496], [841, 699, 1654351420507], [816, 710, 1654351420517], [792, 716, 1654351420528], [761, 725, 1654351420545], [696, 741, 1654351420558], [667, 745, 1654351420569], [597, 756, 1654351420579], [553, 762, 1654351420590], [508, 768, 1654351420600], [439, 779, 1654351420610], [394, 787, 1654351420622], [349, 795, 1654351420636], [263, 807, 1654351420652], [194, 814, 1654351420665], [141, 817, 1654351420675], [130, 817, 1654351420686], [109, 817, 1654351420703], [67, 817, 1654351420719], [44, 815, 1654351420731], [33, 814, 1654351420743], [26, 813, 1654351420754], [9, 812, 1654351420766], [6, 812, 1654351420777], [3, 810, 1654351420788], [3, 809, 1654351420799], [3, 806, 1654351420812], [3, 804, 1654351420824], [3, 801, 1654351420836], [3, 795, 1654351420847], [3, 792, 1654351420858], [4, 787, 1654351420874], [4, 783, 1654351420888], [4, 780, 1654351420899], [5, 771, 1654351420913], [7, 757, 1654351420927], [7, 755, 1654351420941], [7, 749, 1654351420953], [8, 745, 1654351420965], [8, 744, 1654351420977], [9, 741, 1654351420988], [9, 737, 1654351420999], [10, 732, 1654351421011], [10, 727, 1654351421022], [10, 725, 1654351421033], [10, 724, 1654351421044], [10, 721, 1654351421055], [10, 719, 1654351421067], [10, 716, 1654351421077], [10, 714, 1654351421090], [11, 711, 1654351421102]] 15 | # trace = [[16, 2, 1654352029733], [16, 2, 1654352029737], [16, 5, 1654352029741], [16, 9, 1654352029748], [16, 12, 1654352029754], [16, 18, 1654352029763], [16, 23, 1654352029769], [16, 28, 1654352029777], [16, 34, 1654352029785], [15, 38, 1654352029796], [15, 43, 1654352029800], [15, 50, 1654352029812], [15, 57, 1654352029816], [14, 64, 1654352029826], [13, 72, 1654352029833], [13, 79, 1654352029843], [12, 93, 1654352029849], [11, 101, 1654352029860], [10, 109, 1654352029868], [9, 116, 1654352029874], [8, 130, 1654352029881], [7, 138, 1654352029889], [7, 146, 1654352029896], [7, 159, 1654352029904], [7, 167, 1654352029912], [6, 178, 1654352029920], [4, 195, 1654352029928], [3, 200, 1654352029936], [2, 211, 1654352029944], [1, 222, 1654352029954], [0, 236, 1654352029962], [0, 247, 1654352029973], [0, 260, 1654352029983], [0, 273, 1654352029988], [0, 287, 1654352029995], [0, 302, 1654352030003], [0, 312, 1654352030012], [0, 332, 1654352030022], [0, 346, 1654352030029], [0, 357, 1654352030039], [0, 368, 1654352030048], [0, 379, 1654352030054], [0, 395, 1654352030060], [0, 413, 1654352030067], [0, 435, 1654352030076], [2, 462, 1654352030081], [3, 474, 1654352030093], [5, 497, 1654352030097], [7, 513, 1654352030109], [8, 525, 1654352030115], [8, 533, 1654352030125], [9, 541, 1654352030132], [9, 545, 1654352030142], [9, 551, 1654352030149], [9, 556, 1654352030158], [9, 565, 1654352030164], [9, 571, 1654352030171], [9, 576, 1654352030182], [9, 582, 1654352030189], [9, 587, 1654352030199], [8, 595, 1654352030206], [8, 604, 1654352030213], [8, 609, 1654352030221], [8, 613, 1654352030231], [8, 618, 1654352030239], [7, 622, 1654352030243], [7, 626, 1654352030250], [7, 628, 1654352030258], [7, 632, 1654352030266], [7, 633, 1654352030274], [7, 636, 1654352030282], [7, 638, 1654352030290], [7, 640, 1654352030298], [7, 644, 1654352030306], [7, 646, 1654352030318], [8, 650, 1654352030326], [8, 652, 1654352030331], [8, 654, 1654352030343], [8, 658, 1654352030349], [8, 660, 1654352030358], [8, 664, 1654352030364], [8, 665, 1654352030375], [9, 671, 1654352030387], [9, 673, 1654352030392], [9, 677, 1654352030400], [9, 682, 1654352030407], [10, 686, 1654352030414], [10, 689, 1654352030424], [10, 691, 1654352030431], [10, 693, 1654352030440], [10, 694, 1654352030446], [10, 695, 1654352030455], [10, 696, 1654352030467], [10, 697, 1654352030474], [10, 698, 1654352030482], [10, 700, 1654352030487], [10, 701, 1654352030496], [10, 702, 1654352030503], [10, 703, 1654352030519], [10, 704, 1654352030542], [10, 705, 1654352030558], [10, 706, 1654352030574], [10, 707, 1654352030598], [10, 708, 1654352030614], [9, 708, 1654352030622], [9, 709, 1654352030639], [9, 710, 1654352030725], [9, 711, 1654352030733], [9, 712, 1654352030745]] 16 | # trace = [[854, 715, 1654443055876], [854, 715, 1654443055880], [838, 715, 1654443055885], [826, 715, 1654443055889], [806, 715, 1654443055899], [793, 716, 1654443055916], [782, 716, 1654443055920], [759, 716, 1654443055927], [732, 716, 1654443055932], [705, 716, 1654443055938], [678, 716, 1654443055949], [644, 716, 1654443055953], [617, 716, 1654443055968], [597, 716, 1654443055975], [556, 716, 1654443055981], [531, 716, 1654443055986], [497, 716, 1654443055996], [470, 716, 1654443056000], [453, 716, 1654443056007], [435, 716, 1654443056015], [428, 716, 1654443056029], [415, 716, 1654443056032], [408, 716, 1654443056041], [404, 716, 1654443056047], [396, 716, 1654443056057], [392, 716, 1654443056067], [388, 716, 1654443056073], [386, 716, 1654443056085], [385, 717, 1654443056093], [384, 717, 1654443056106], [383, 717, 1654443056132], [381, 717, 1654443056829], [380, 717, 1654443056845], [379, 717, 1654443056855], [378, 717, 1654443056862], [376, 717, 1654443056873], [374, 717, 1654443056881], [368, 717, 1654443056890], [365, 717, 1654443056903], [361, 717, 1654443056907], [355, 717, 1654443056912], [348, 717, 1654443056921], [339, 717, 1654443056930], [333, 717, 1654443056938], [324, 717, 1654443056949], [309, 717, 1654443056954], [296, 717, 1654443056963], [274, 717, 1654443056970], [261, 717, 1654443056977], [243, 717, 1654443056986], [230, 717, 1654443056992], [215, 716, 1654443057000], [203, 716, 1654443057010], [192, 715, 1654443057016], [179, 714, 1654443057031], [170, 714, 1654443057033], [161, 713, 1654443057038], [156, 712, 1654443057045], [150, 712, 1654443057053], [145, 712, 1654443057061], [135, 712, 1654443057070], [130, 712, 1654443057079], [128, 712, 1654443057086], [125, 712, 1654443057093], [119, 712, 1654443057102], [114, 712, 1654443057109], [109, 712, 1654443057123], [103, 712, 1654443057129], [94, 712, 1654443057139], [88, 712, 1654443057147], [82, 712, 1654443057157], [79, 712, 1654443057161], [75, 712, 1654443057174], [71, 712, 1654443057178], [68, 712, 1654443057187], [67, 712, 1654443057193], [64, 712, 1654443057202], [62, 712, 1654443057219], [61, 712, 1654443057225], [59, 712, 1654443057231], [56, 712, 1654443057236], [54, 712, 1654443057246], [51, 712, 1654443057251], [45, 712, 1654443057257], [40, 712, 1654443057264], [32, 713, 1654443057271], [29, 713, 1654443057279], [26, 713, 1654443057298], [24, 713, 1654443057302], [23, 713, 1654443057310], [22, 713, 1654443057325], [21, 713, 1654443057376], [20, 713, 1654443057406]] 17 | 18 | # 跳变轨迹 19 | # trace1 = [[6, 83, 1654487346464], [6, 240, 1654487347624], [6, 376, 1654487348740], [285, 601, 1654487349821], [305, 601, 1654487350358], [325, 601, 1654487350905], [345, 601, 1654487351443], [365, 601, 1654487351988], [385, 601, 1654487352522], [405, 601, 1654487353069], [425, 601, 1654487353618], [445, 601, 1654487354165], [465, 601, 1654487354703], [485, 601, 1654487355248], [505, 601, 1654487355795], [525, 601, 1654487356322], [545, 601, 1654487356874], [565, 601, 1654487357419], [585, 601, 1654487357972], [605, 601, 1654487358505], [625, 601, 1654487359038], [645, 601, 1654487359589], [15, 721, 1654487361263]] 20 | 21 | #计算机横竖直线 22 | # trace1 = [[867, 2, 1654676395837], [874, 6, 1654676395888], [881, 11, 1654676395954], [888, 15, 1654676396020], [895, 20, 1654676396087], [902, 24, 1654676396154], [909, 28, 1654676396220], [916, 33, 1654676396287], [923, 37, 1654676396354], [930, 42, 1654676396420], [937, 46, 1654676396486], [944, 51, 1654676396554], [951, 55, 1654676396620], [958, 59, 1654676396687], [965, 64, 1654676396754], [972, 68, 1654676396820], [979, 73, 1654676396887], [986, 77, 1654676396954], [993, 82, 1654676397020], [1000, 86, 1654676397087], [1000, 101, 1654676397336], [1000, 116, 1654676397403], [1000, 131, 1654676397470], [1000, 146, 1654676397538], [1000, 161, 1654676397604], [1000, 176, 1654676397670], [1000, 191, 1654676397737], [1000, 206, 1654676397819], [1000, 221, 1654676397869], [1000, 236, 1654676397927], [1000, 251, 1654676397992], [1000, 266, 1654676398053], [1000, 281, 1654676398119], [1000, 296, 1654676398188], [1000, 311, 1654676398249], [1000, 326, 1654676398313], [1000, 341, 1654676398374], [1000, 356, 1654676398453], [1000, 371, 1654676398502], [1000, 386, 1654676398561], [1000, 401, 1654676398637], [1000, 416, 1654676398685], [1000, 431, 1654676398754], [1000, 446, 1654676398819], [1000, 461, 1654676398887], [1000, 476, 1654676398954], [1000, 491, 1654676399020], [1000, 506, 1654676399087], [1000, 521, 1654676399154], [1000, 536, 1654676399221], [1000, 551, 1654676399287], [1000, 566, 1654676399354], [1000, 581, 1654676399429], [1000, 596, 1654676399487], [1000, 611, 1654676399557], [1000, 626, 1654676399621], [1000, 641, 1654676399693], [1000, 656, 1654676399758], [1000, 671, 1654676399810], [1000, 686, 1654676399875], [980, 686, 1654676400122], [960, 686, 1654676400171], [940, 686, 1654676400242], [920, 686, 1654676400307], [900, 686, 1654676400373], [880, 686, 1654676400456], [860, 686, 1654676400502], [840, 686, 1654676400571], [820, 686, 1654676400637], [800, 686, 1654676400704], [780, 686, 1654676400770], [760, 686, 1654676400838], [740, 686, 1654676400904], [720, 686, 1654676400972], [700, 686, 1654676401042], [680, 686, 1654676401109], [660, 686, 1654676401174], [640, 686, 1654676401243], [620, 686, 1654676401310], [600, 686, 1654676401371], [580, 686, 1654676401434], [560, 686, 1654676401504], [540, 686, 1654676401571], [520, 686, 1654676401637], [500, 686, 1654676401704], [480, 686, 1654676401771], [460, 686, 1654676401840], [440, 686, 1654676401910], [420, 686, 1654676401975], [400, 686, 1654676402042], [380, 686, 1654676402109], [360, 686, 1654676402174], [340, 686, 1654676402241], [320, 686, 1654676402309], [300, 686, 1654676402375], [280, 686, 1654676402441], [260, 686, 1654676402508], [240, 686, 1654676402576], [220, 686, 1654676402642], [200, 686, 1654676402704], [199, 686, 1654676403682], [193, 687, 1654676403702], [187, 688, 1654676403714], [182, 688, 1654676403736], [178, 689, 1654676403752], [177, 689, 1654676403770], [172, 690, 1654676403786], [161, 690, 1654676403802], [151, 692, 1654676403819], [142, 692, 1654676403835], [135, 694, 1654676403853], [129, 696, 1654676403869], [124, 698, 1654676403887], [118, 699, 1654676403902], [113, 700, 1654676403919], [105, 702, 1654676403937], [99, 703, 1654676403952], [92, 705, 1654676403969], [89, 706, 1654676403986], [85, 708, 1654676404004], [74, 711, 1654676404036], [71, 712, 1654676404052], [57, 714, 1654676404069], [52, 716, 1654676404085], [47, 717, 1654676404103], [43, 717, 1654676404120], [40, 718, 1654676404136], [35, 719, 1654676404152], [32, 719, 1654676404170], [27, 720, 1654676404186], [25, 720, 1654676404204], [23, 720, 1654676404220], [22, 720, 1654676404236], [21, 720, 1654676404253], [21, 721, 1654676404269]] 23 | 24 | # #计算机斜线 25 | # trace2 = [[854, 0, 1654674804567], [861, 4, 1654674804634], [868, 8, 1654674804701], [875, 12, 1654674804767], [883, 17, 1654674804834], [890, 21, 1654674804902], [897, 25, 1654674804966], [905, 30, 1654674805034], [912, 34, 1654674805101], [919, 38, 1654674805166], [927, 43, 1654674805234], [934, 47, 1654674805300], [941, 51, 1654674805367], [949, 56, 1654674805435], [956, 60, 1654674805500], [963, 64, 1654674805567], [971, 69, 1654674805633], [978, 73, 1654674805700], [985, 77, 1654674805767], [993, 82, 1654674805834], [1000, 86, 1654674805900], [978, 106, 1654674806133], [955, 126, 1654674806184], [932, 146, 1654674806250], [910, 166, 1654674806317], [888, 186, 1654674806383], [865, 206, 1654674806451], [842, 227, 1654674806517], [820, 247, 1654674806584], [798, 267, 1654674806651], [775, 287, 1654674806717], [752, 307, 1654674806784], [730, 327, 1654674806850], [708, 347, 1654674806917], [685, 367, 1654674806985], [662, 387, 1654674807051], [640, 407, 1654674807116], [618, 427, 1654674807182], [595, 447, 1654674807251], [572, 467, 1654674807316], [550, 488, 1654674807384], [528, 508, 1654674807453], [505, 528, 1654674807522], [482, 548, 1654674807588], [460, 568, 1654674807654], [438, 588, 1654674807721], [415, 608, 1654674807783], [392, 628, 1654674807855], [370, 648, 1654674807921], [348, 668, 1654674807992], [325, 688, 1654674808057], [302, 708, 1654674808122], [280, 728, 1654674808188], [258, 748, 1654674808239], [235, 769, 1654674808304], [212, 789, 1654674808371], [190, 809, 1654674808441], [168, 829, 1654674808504], [145, 849, 1654674808555], [122, 869, 1654674808621], [100, 889, 1654674808687], [96, 889, 1654674809913], [91, 889, 1654674809933], [83, 889, 1654674809947], [81, 889, 1654674809966], [81, 888, 1654674810042], [80, 885, 1654674810066], [77, 878, 1654674810083], [71, 865, 1654674810099], [66, 856, 1654674810116], [62, 848, 1654674810132], [56, 836, 1654674810150], [51, 826, 1654674810166], [44, 813, 1654674810183], [39, 805, 1654674810199], [32, 794, 1654674810217], [28, 787, 1654674810233], [24, 781, 1654674810251], [22, 779, 1654674810267], [20, 775, 1654674810284], [19, 774, 1654674810300], [17, 770, 1654674810317], [14, 765, 1654674810334], [13, 761, 1654674810350], [11, 755, 1654674810365], [9, 751, 1654674810383], [8, 745, 1654674810399], [7, 741, 1654674810417], [6, 736, 1654674810432], [6, 733, 1654674810449], [5, 731, 1654674810468], [5, 729, 1654674810483], [5, 728, 1654674810500], [4, 727, 1654674810516], [4, 726, 1654674810568]] 26 | # 27 | # trace3=[[159, 4, 1654782791793], [157, 19, 1654782791807], [156, 30, 1654782791823], [154, 38, 1654782791839], [153, 48, 1654782791856], [151, 58, 1654782791869], [150, 72, 1654782791885], [147, 84, 1654782791900], [145, 93, 1654782791917], [141, 113, 1654782791932], [139, 122, 1654782791948], [135, 142, 1654782791966], [132, 168, 1654782791979], [131, 178, 1654782791994], [130, 191, 1654782792011], [129, 211, 1654782792027], [128, 221, 1654782792041], [128, 242, 1654782792058], [128, 265, 1654782792074], [127, 272, 1654782792088], [127, 283, 1654782792104], [125, 297, 1654782792119], [124, 307, 1654782792135], [123, 314, 1654782792151], [121, 329, 1654782792167], [121, 339, 1654782792183], [120, 347, 1654782792199], [117, 369, 1654782792214], [115, 385, 1654782792229], [112, 396, 1654782792245], [108, 415, 1654782792260], [105, 426, 1654782792277], [103, 432, 1654782792294], [100, 442, 1654782792307], [98, 446, 1654782792325], [95, 455, 1654782792340], [92, 463, 1654782792354], [91, 469, 1654782792369], [88, 477, 1654782792386], [87, 485, 1654782792402], [86, 490, 1654782792417], [84, 499, 1654782792432], [81, 510, 1654782792449], [78, 522, 1654782792464], [75, 530, 1654782792479], [70, 543, 1654782792495], [68, 548, 1654782792512], [64, 558, 1654782792531], [57, 575, 1654782792543], [55, 580, 1654782792559], [50, 600, 1654782792573], [48, 609, 1654782792589], [45, 630, 1654782792604], [42, 650, 1654782792622], [40, 661, 1654782792635], [38, 676, 1654782792650], [36, 684, 1654782792666], [34, 691, 1654782792684], [34, 693, 1654782792697], [34, 695, 1654782792712], [33, 696, 1654782792731], [33, 697, 1654782792745], [33, 699, 1654782792760], [33, 701, 1654782792791], [32, 703, 1654782792808], [32, 705, 1654782792839], [32, 706, 1654782792853], [31, 708, 1654782792872], [31, 710, 1654782792888], [30, 711, 1654782792902], [30, 712, 1654782792920], [30, 713, 1654782793058], [28, 714, 1654782793150], [28, 715, 1654782793197], [27, 716, 1654782793228], [25, 718, 1654782793258], [24, 720, 1654782793276], [24, 721, 1654782793291], [23, 722, 1654782793307], [21, 722, 1654782793324], [21, 723, 1654782793343], [22, 724, 1654782793500]] 28 | # 29 | # trace2=[[159, 4, 1654782798807], [159, 4, 1654782798813], [157, 19, 1654782798819], [156, 30, 1654782798832], [154, 38, 1654782798848], [153, 48, 1654782798864], [151, 58, 1654782798879], [150, 72, 1654782798896], [147, 84, 1654782798909], [145, 93, 1654782798925], [141, 113, 1654782798943], [139, 122, 1654782798956], [135, 142, 1654782798974], [132, 168, 1654782798988], [131, 178, 1654782799005], [130, 191, 1654782799022], [129, 211, 1654782799036], [128, 221, 1654782799053], [128, 242, 1654782799069], [128, 265, 1654782799085], [127, 272, 1654782799100], [127, 283, 1654782799114], [125, 297, 1654782799131], [124, 307, 1654782799149], [123, 314, 1654782799168], [121, 329, 1654782799177], [121, 339, 1654782799192], [120, 347, 1654782799207], [117, 369, 1654782799237], [115, 385, 1654782799244], [112, 396, 1654782799253], [108, 415, 1654782799270], [105, 426, 1654782799285], [103, 432, 1654782799302], [100, 442, 1654782799317], [98, 446, 1654782799333], [95, 455, 1654782799348], [92, 463, 1654782799364], [91, 469, 1654782799380], [88, 477, 1654782799395], [87, 485, 1654782799410], [86, 490, 1654782799427], [84, 499, 1654782799442], [81, 510, 1654782799459], [78, 522, 1654782799473], [75, 530, 1654782799490], [70, 543, 1654782799507], [68, 548, 1654782799523], [64, 558, 1654782799538], [57, 575, 1654782799553], [55, 580, 1654782799569], [50, 600, 1654782799585], [48, 609, 1654782799603], [45, 630, 1654782799617], [42, 650, 1654782799634], [40, 661, 1654782799651], [38, 676, 1654782799665], [36, 684, 1654782799682], [34, 691, 1654782799697], [34, 693, 1654782799714], [34, 695, 1654782799729], [33, 696, 1654782799746], [33, 697, 1654782799761], [33, 699, 1654782799784], [33, 701, 1654782799810], [32, 703, 1654782799825], [32, 705, 1654782799855], [32, 706, 1654782799871], [31, 708, 1654782799888], [31, 710, 1654782799903], [30, 711, 1654782799921], [30, 712, 1654782799937], [30, 713, 1654782800092], [28, 714, 1654782800154], [28, 715, 1654782800185], [27, 716, 1654782800217], [25, 718, 1654782800248], [24, 720, 1654782800265], [24, 721, 1654782800280], [23, 722, 1654782800294], [21, 722, 1654782800313], [21, 723, 1654782800327], [22, 724, 1654782800486]] 30 | # 31 | # trace1=[[162, 2, 1654782935984], [162, 2, 1654782935990], [162, 6, 1654782935998], [162, 10, 1654782936003], [162, 14, 1654782936009], [162, 20, 1654782936014], [162, 27, 1654782936023], [162, 33, 1654782936030], [162, 37, 1654782936037], [161, 44, 1654782936045], [160, 51, 1654782936054], [159, 57, 1654782936061], [155, 70, 1654782936068], [154, 77, 1654782936077], [151, 88, 1654782936085], [151, 95, 1654782936093], [149, 102, 1654782936101], [147, 116, 1654782936108], [147, 123, 1654782936117], [145, 130, 1654782936124], [143, 142, 1654782936133], [141, 153, 1654782936141], [139, 161, 1654782936148], [133, 182, 1654782936157], [130, 192, 1654782936165], [129, 201, 1654782936173], [123, 223, 1654782936181], [121, 236, 1654782936189], [118, 260, 1654782936198], [115, 282, 1654782936205], [114, 292, 1654782936213], [111, 312, 1654782936221], [109, 327, 1654782936229], [107, 337, 1654782936238], [104, 358, 1654782936245], [102, 368, 1654782936253], [100, 388, 1654782936261], [98, 410, 1654782936268], [96, 417, 1654782936279], [95, 437, 1654782936285], [95, 454, 1654782936295], [95, 468, 1654782936301], [95, 477, 1654782936310], [95, 483, 1654782936319], [94, 489, 1654782936327], [93, 496, 1654782936335], [93, 501, 1654782936344], [92, 507, 1654782936350], [91, 513, 1654782936359], [90, 520, 1654782936367], [89, 530, 1654782936375], [89, 539, 1654782936383], [88, 544, 1654782936390], [87, 554, 1654782936399], [86, 559, 1654782936407], [85, 565, 1654782936415], [83, 572, 1654782936423], [81, 577, 1654782936431], [80, 584, 1654782936439], [78, 590, 1654782936448], [78, 595, 1654782936454], [77, 602, 1654782936463], [76, 608, 1654782936470], [74, 616, 1654782936481], [73, 618, 1654782936490], [69, 625, 1654782936497], [67, 628, 1654782936509], [65, 631, 1654782936514], [63, 634, 1654782936521], [61, 636, 1654782936530], [58, 641, 1654782936538], [56, 645, 1654782936548], [54, 649, 1654782936554], [52, 653, 1654782936563], [49, 657, 1654782936570], [48, 660, 1654782936577], [47, 662, 1654782936589], [46, 664, 1654782936596], [45, 666, 1654782936603], [44, 669, 1654782936612], [43, 670, 1654782936621], [42, 673, 1654782936629], [41, 677, 1654782936638], [39, 681, 1654782936643], [37, 685, 1654782936650], [35, 690, 1654782936658], [34, 693, 1654782936665], [33, 696, 1654782936673], [31, 699, 1654782936680], [29, 703, 1654782936689], [27, 705, 1654782936696], [25, 708, 1654782936704], [23, 711, 1654782936713], [22, 714, 1654782936721], [20, 716, 1654782936730], [19, 719, 1654782936736], [18, 720, 1654782936746], [17, 721, 1654782936753], [16, 722, 1654782936761], [15, 723, 1654782936769], [15, 724, 1654782936809], [15, 724, 1654782936917]] 32 | # 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /examples/use_selenium_jump.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver import ActionChains 4 | import time 5 | 6 | 7 | def simulate_answer(): 8 | time.sleep(5) 9 | driver.find_element(By.XPATH, "/html/body/input[1]").click() 10 | time.sleep(1) 11 | driver.find_element(By.XPATH, "/html/body/input[6]").click() 12 | time.sleep(1) 13 | driver.find_element(By.XPATH, "/html/body/input[10]").click() 14 | time.sleep(1) 15 | slider = driver.find_element(By.XPATH, "/html/body/div[1]/div[1]") 16 | ActionChains(driver).click_and_hold(slider).perform() 17 | i = 0 18 | distance = 358 19 | while i <= distance: 20 | ActionChains(driver).move_by_offset(20, 0).perform() 21 | i += 20 22 | ActionChains(driver).release().perform() 23 | time.sleep(1) 24 | driver.find_element(By.XPATH, "/html/body/button").click() 25 | time.sleep(1) 26 | 27 | 28 | if __name__ == '__main__': 29 | driver = webdriver.Chrome() 30 | driver.get("file:///D:\\work_github\\robot-mouse-track-recognition\\examples\\collect_data.html") 31 | driver.get("file:///D:\\work_github\\robot-mouse-track-recognition\\examples\\collect_data_ap.html") 32 | 33 | simulate_answer() 34 | time.sleep(10) 35 | driver.close() 36 | -------------------------------------------------------------------------------- /imgs/contacts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/imgs/contacts.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | pytest-cover 3 | python-coveralls 4 | numpy 5 | matplotlib 6 | sphinx_markdown_tables 7 | recommonmark -------------------------------------------------------------------------------- /robot_mouse_track/contants.py: -------------------------------------------------------------------------------- 1 | DECOMPOSITION = "decomposition" 2 | COMBINE = "combine" 3 | X = "x" 4 | Y = "y" 5 | -------------------------------------------------------------------------------- /robot_mouse_track/mouse_track.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from robot_mouse_track import contants 4 | 5 | 6 | class MouseTrack: 7 | """ 8 | 鼠标轨迹对象 9 | 10 | :param list[list] trace: 轨迹数组,例如:[[x_1,y_1,timestamp_1],[x_2,y_2,timestamp_2],...] 11 | 12 | :var ndarray arr_trace: 轨迹数组转成的ndarray 13 | :var ndarray arr_time: 时间ndarray 14 | :var int default=20 max_duration_silent: 鼠标在移动的过程中可能会停止。需要定义一个时间间隔,超过多少秒,算静止,将长间隔缩短为一个固定长度 15 | :var int default=100 max_doa_tan: 方向角正切值峰值截断,超过该值,置为np.clip(angle, -max_doa_tan, max_doa_tan) 16 | :var int default=5 max_doa_point: 两个点计算角度的时候,采用的是 arr[i] 和 arr[i+max_doa_point],因为太近的话,误差较大 17 | :var list[ndarray] feature_dev_combine: 合速度的n阶导数 18 | :var list[ndarray] feature_dev_decomposition: 分速度的n阶导数 19 | :var list[ndarray] feature_doa: 方向角 20 | :var list[ndarray] feature_diff_time: 当前时间差 21 | """ 22 | 23 | def __init__(self, trace): 24 | self.arr_trace = np.array(trace, np.float64) 25 | self.arr_time = self.arr_trace[:, -1] 26 | 27 | self.max_duration_silent = 20 28 | 29 | self.max_doa_tan = 100 30 | self.max_doa_point = 5 31 | 32 | self.feature_dev_combine = [] 33 | self.feature_dev_decomposition = [] 34 | self.feature_doa = np.array([]) 35 | self.feature_diff_time = np.array([]) 36 | 37 | self._arr_diff_dis = None 38 | self._arr_diff_time = None 39 | 40 | def get_feature_diff_time(self): 41 | """ 42 | 获取样本点之间的时间差 43 | 44 | :return: 时间差的一维数组 45 | :rtype: ndarray 46 | """ 47 | if len(self.feature_diff_time) > 0: 48 | return self.feature_diff_time 49 | 50 | self.feature_diff_time = self.arr_trace[1:, -1] - self.arr_trace[:-1, -1] 51 | return self.feature_diff_time 52 | 53 | def get_feature_dev(self, order=2, mode=contants.COMBINE): 54 | """ 55 | 计算n-order阶导数 56 | 57 | :param order: 求到第n阶导数 58 | :param mode: 求导的方式。``combine``:对合速度求导; ``decomposition``:对分速度求导 59 | :return: 求导后的结果 60 | :rtype: list[ndarray] 61 | """ 62 | if mode == contants.COMBINE: 63 | feature_dev = self.feature_dev_combine 64 | elif mode == contants.DECOMPOSITION: 65 | feature_dev = self.feature_dev_decomposition 66 | else: 67 | raise Exception("请输入正确的类型") 68 | 69 | if len(feature_dev) >= order: 70 | return feature_dev 71 | 72 | if not feature_dev: # 如果求导阶数不够,则增量计算缺的阶数 73 | self._arr_diff_dis = self.arr_trace[1:, :] - self.arr_trace[:-1, :] 74 | self._arr_diff_time = np.clip(self._arr_diff_dis[:, -1:], 0, self.max_duration_silent) 75 | if mode == contants.COMBINE: 76 | self._arr_diff_dis = (np.sum((self._arr_diff_dis[:, :-1] ** 2), axis=1) ** 0.5)[:, np.newaxis] 77 | else: 78 | self._arr_diff_dis = self._arr_diff_dis[:, :-1] 79 | order_cur = 0 80 | else: 81 | order_cur = len(feature_dev) 82 | 83 | while 1: 84 | arr_dev = self._arr_diff_dis / self._arr_diff_time[:len(self._arr_diff_dis)] 85 | feature_dev.append(arr_dev) 86 | order_cur += 1 87 | if order_cur >= order: 88 | break 89 | self._arr_diff_dis = arr_dev[1:] - arr_dev[:-1] 90 | 91 | return feature_dev 92 | 93 | def show_track(self, x_min=-100, x_max=1920, y_min=-100, y_max=1280): 94 | """ 95 | 画出鼠标轨迹 96 | 97 | :param int default=-100 x_min: 横坐标最小值 98 | :param int default=1920 x_max: 横坐标最大值 99 | :param int default=-100 y_min: 纵坐标最小值 100 | :param int default=1280 y_max: 纵坐标最大值 101 | :return: None 102 | """ 103 | _, axis = plt.subplots(1, 1) 104 | axis.invert_yaxis() 105 | plt.plot(self.arr_trace[:, 0], self.arr_trace[:, 1], ".") 106 | axis.set_xlim((x_min, x_max)) 107 | axis.set_ylim((y_max, y_min)) 108 | plt.title("trace xy") 109 | # plt.show() 110 | 111 | def get_feature_doa(self): 112 | """ 113 | 计算方向角变化 114 | 115 | :return: 返回方向角的变化特征 116 | :rtype: ndarray 117 | """ 118 | if len(self.feature_doa) > 0: 119 | return self.feature_doa 120 | 121 | arr_diff_dis = self.arr_trace[self.max_doa_point:, :-1] - self.arr_trace[:-self.max_doa_point, :-1] 122 | # 防止除以0 123 | arr_diff_dis[:, 0][np.where(arr_diff_dis[:, 0] == 0)] = 10e-8 124 | 125 | self.feature_doa = np.clip(arr_diff_dis[:, 1] / arr_diff_dis[:, 0], -self.max_doa_tan, self.max_doa_tan) 126 | 127 | self.feature_doa = np.arctan(self.feature_doa) * 180 / np.pi 128 | return self.feature_doa 129 | 130 | 131 | # if __name__ == '__main__': 132 | # from examples import trace_examples 133 | # 134 | # mt = MouseTrack(trace_examples.trace1) 135 | # x = mt.get_feature_dev(order=1, mode=contants.COMBINE) 136 | # y = mt.get_feature_dev(order=2, mode=contants.COMBINE) 137 | # print(x) 138 | # print(y) 139 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_constant_velocity.py: -------------------------------------------------------------------------------- 1 | from robot_mouse_track.mouse_track import MouseTrack 2 | import numpy as np 3 | from robot_mouse_track.utils import small_runs 4 | from robot_mouse_track import contants 5 | 6 | 7 | class ConstantVelocityMotion: 8 | """ 9 | 分速度的匀速运动 10 | 分速度的匀变速运动 11 | 分速度的匀变加速运动 12 | 合速度的匀速运动 13 | 合速度的匀变速运动 14 | 合速度的匀变加速运动 15 | 16 | :var str default="combine" direction: 求导方向。 "x":对 ``x`` 分量求导;"y":对 ``y`` 分量求导;"combine":对合速度 ``combine`` 求导 17 | :var int default=2 n_order_dev: 距离对时间的几阶导数 1阶是速度 2阶是加速度 3阶是加速度的变化速率 18 | :var int default=5 least_point: 最少要包含的点的个数 19 | :var int default=100 least_length: 最少移动的距离 20 | :var float default=0.01 th_span: 两点之间的最大变化幅度,低于这个值,则认为是风险 21 | """ 22 | 23 | def __init__(self): 24 | self.direction = contants.COMBINE 25 | self.n_order_dev = 2 26 | self.least_point = 5 27 | self.least_length = 100 28 | self.th_span = 0.01 29 | 30 | def judge_risk(self, mouse_track: MouseTrack): 31 | """ 32 | 风险判定 33 | 34 | :param MouseTrack mouse_track: 鼠标轨迹对象 35 | :return: (have_risk, risk_level) 36 | :rtype: (bool, float) 37 | """ 38 | arr_dev = "" 39 | if self.direction in [contants.X, contants.Y]: 40 | feature_dev = mouse_track.get_feature_dev(order=self.n_order_dev, mode=contants.DECOMPOSITION) 41 | if self.direction == contants.X: 42 | arr_dev = feature_dev[self.n_order_dev - 1][:, 0] 43 | elif self.direction == contants.Y: 44 | arr_dev = feature_dev[self.n_order_dev - 1][:, 1] 45 | elif self.direction == contants.COMBINE: 46 | feature_dev = mouse_track.get_feature_dev(order=self.n_order_dev, mode=contants.COMBINE) 47 | arr_dev = feature_dev[self.n_order_dev - 1] 48 | else: 49 | raise Exception("请输入正确的类型") 50 | 51 | lst_small = small_runs(arr_dev.reshape(-1), span=self.th_span) 52 | 53 | min_span = 1000000 54 | for left, right in lst_small: 55 | if right - left + 1 < self.least_point: 56 | # 如果该直线上的点的个数少,则不考虑 57 | continue 58 | 59 | point1 = mouse_track.arr_trace[left, :-1] 60 | point2 = mouse_track.arr_trace[right, :-1] 61 | length = np.sum((point2 - point1) ** 2) ** 0.5 62 | if length < self.least_length: 63 | # 如果该直线的长度小,则不考虑 64 | continue 65 | 66 | if right - left + 1 >= self.least_point + 4: 67 | arr_part = arr_dev[left + 2:right - 2 + 1] 68 | elif right - left + 1 >= self.least_point + 2: 69 | arr_part = arr_dev[left + 1:right - 1 + 1] 70 | else: 71 | arr_part = arr_dev[left:right + 1] 72 | 73 | # 如果长度较大,则切头去尾(头尾可能有异常变化点),再算span 74 | span = arr_part.max() - arr_part.min() 75 | if span < min_span: 76 | min_span = span 77 | if min_span == 0: min_span = 0.0000001 78 | exceed_times = self.th_span / min_span 79 | if exceed_times > 1.0: 80 | return True, exceed_times 81 | return False, exceed_times 82 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_jump.py: -------------------------------------------------------------------------------- 1 | from ..mouse_track import MouseTrack 2 | from .. import contants 3 | import numpy as np 4 | 5 | 6 | class JumpMotion: 7 | """ 8 | 鼠标跳跃运动 9 | 10 | :var int default=20 th_velocity: 每毫秒移动的像素个数 超过该值,就认为是风险 11 | :var float default=1.4 th_acceleration: 每毫秒的加速度 超过该值,就认为是风险 12 | """ 13 | 14 | def __init__(self, th_velocity=20, th_acceleration=1.4): 15 | self.th_velocity = th_velocity 16 | self.th_acceleration = th_acceleration 17 | 18 | def judge_risk(self, mouse_track: MouseTrack): 19 | """ 20 | 风险判定 21 | 22 | :param MouseTrack mouse_track: 鼠标轨迹对象 23 | :return: (have_risk, velocity_risk_level, acceleration_risk_level) 24 | :rtype: bool, (float, float) 25 | """ 26 | feature_dev = mouse_track.get_feature_dev(order=2, mode=contants.COMBINE) 27 | arr_velocity = feature_dev[0] 28 | arr_acceleration = feature_dev[1] 29 | 30 | exceed_times_velocity = np.max(arr_velocity) / self.th_velocity 31 | exceed_times_acceleration = np.max(arr_acceleration) / self.th_acceleration 32 | if exceed_times_velocity > 1.0 or exceed_times_acceleration > 1.0: 33 | return True, (exceed_times_velocity, exceed_times_acceleration) 34 | return False, (exceed_times_velocity, exceed_times_acceleration) 35 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_linear.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from robot_mouse_track.mouse_track import MouseTrack 3 | from robot_mouse_track.utils import small_runs 4 | 5 | 6 | class LinearMotion: 7 | """ 8 | 斜直线运动(人手可能会画出横/竖直线,但是画不出来斜直线) 9 | 10 | :var int default=5 least_point: 这条线上至少有多少个点 11 | :var int default=200 th_length: 斜线运动长度超过多少,认为是风险,单位px 12 | :var float default=0.1 th_span: 两点之间的最大方向角变化幅度,低于这个值,则认为是风险 13 | """ 14 | 15 | def __init__(self): 16 | self.least_point = 5 # 这条线上至少有多少个点 17 | self.th_length = 200 # 斜线运动长度超过多少,认为是风险,单位px 18 | self.th_span = 0.1 19 | 20 | def judge_risk(self, mouse_track: MouseTrack): 21 | """ 22 | 风险判定 23 | 24 | :param MouseTrack mouse_track: 鼠标轨迹对象 25 | :return: (have_risk, risk_level) 26 | :rtype: (bool, float) 27 | """ 28 | 29 | # n个点算斜率,斜率相近表示平行 30 | feature_doa = mouse_track.get_feature_doa() 31 | 32 | # 斜率变化幅度较小则认为是斜线 33 | # 获取斜率变化幅度较小的片段的左右闭区间 34 | lst_small = small_runs(feature_doa, span=self.th_span) 35 | max_length = 0 36 | for left, right in lst_small: 37 | if right - left + 1 < self.least_point: 38 | # 如果该直线上的点的个数少,则不考虑 39 | continue 40 | point1 = mouse_track.arr_trace[left, :-1] 41 | point2 = mouse_track.arr_trace[right, :-1] 42 | length = np.sum((point2 - point1) ** 2) ** 0.5 43 | if length < self.th_length: 44 | # 如果该直线的长度小,则不考虑 45 | continue 46 | if length > max_length: # 获取该轨迹中最长的直线长度 47 | max_length = length 48 | 49 | exceed_times_length = max_length / self.th_length 50 | if exceed_times_length > 1.0: 51 | return True, exceed_times_length 52 | return False, exceed_times_length 53 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_similar.py: -------------------------------------------------------------------------------- 1 | from robot_mouse_track.mouse_track import MouseTrack 2 | import numpy as np 3 | 4 | 5 | def calc_vec(mouse_track: MouseTrack, len_x=1920, len_y=1280, bin_split_nx=4, bin_split_ny=4): 6 | """ 7 | 计算鼠标轨迹的特征向量 8 | 9 | :param MouseTrack mouse_track: 鼠标轨迹对象 10 | :param int default=1920 len_x: 屏幕横向的像素点个数 11 | :param int default=1280 len_y: 屏幕纵向的像素点个数 12 | :param int default=4 bin_split_nx: 屏幕横向的像素点 分成几个等宽的桶(可以提升鲁棒性,但不能太大,太大就会损失精确性) 13 | :param int default=4 bin_split_ny: 屏幕纵向的像素点 分成几个等宽的桶(可以提升鲁棒性,但不能太大,太大就会损失精确性) 14 | :return: 特征向量 15 | :rtype: ndarray ``shape=(1,len_x/bin_split_nx+len_y/bin_split_ny)`` 16 | """ 17 | hist_x, _ = np.histogram(mouse_track.arr_trace[:, 0], bins=len_x // bin_split_nx, 18 | range=(0, len_x), density=True) 19 | hist_y, _ = np.histogram(mouse_track.arr_trace[:, 1], bins=len_y // bin_split_ny, 20 | range=(0, len_y), density=True) 21 | return np.r_[hist_x, hist_y] 22 | 23 | 24 | class SimilarMotion: 25 | """ 26 | 路径重复的运动(防止一些未知的鼠标录制软件可以躲过以上防御,这里可以加最后一层防御) 27 | 28 | :var float default=0.001 th_score_diff: 差异阈值,低于这个值,则认为是风险 29 | """ 30 | 31 | def __init__(self): 32 | self.th_score_diff = 0.001 33 | 34 | def judge_risk(self, vec, lst_vec_bank): 35 | """ 36 | 风险判定 37 | 38 | :param ndarray vec: 鼠标轨迹的特征向量 39 | :param list[ndarray] lst_vec_bank: 鼠标轨迹的特征向量列表,实践中可以为每个用户维护了一个向量池,防止用户使用多段录像交替攻击 40 | :return: (have_risk, risk_level) 41 | :rtype: (bool, float) 42 | """ 43 | arr_vec_bank = np.array(lst_vec_bank) 44 | arr_res = np.sum((arr_vec_bank - vec) ** 2, axis=1) 45 | min_score = min(arr_res) 46 | if min_score == 0: 47 | min_score = 0.000001 48 | exceed_times = self.th_score_diff / min_score 49 | if exceed_times > 1: 50 | return True, exceed_times 51 | return False, exceed_times 52 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_slow.py: -------------------------------------------------------------------------------- 1 | from robot_mouse_track.mouse_track import MouseTrack 2 | import numpy as np 3 | 4 | 5 | class SlowMotion: 6 | """ 7 | 轨迹点间 时间间隔非常大的运动(比如pyautogui、鼠标录制软件【普通速度】) 8 | 9 | :var int default=15 th_slow: 超过多少毫秒的移动 算作 缓慢 10 | :var float default=0.5 th_length: 缓慢移动的次数占比。超过该值判定为风险 11 | """ 12 | 13 | def __init__(self): 14 | self.th_slow = 15 15 | self.th_slow_rate = 0.5 16 | 17 | def judge_risk(self, mouse_track: MouseTrack): 18 | """ 19 | 风险判定 20 | 21 | :param MouseTrack mouse_track: 鼠标轨迹对象 22 | :return: (have_risk, risk_level) 23 | :rtype: (bool, float) 24 | """ 25 | feature_diff_time = mouse_track.get_feature_diff_time() 26 | 27 | num_slow = np.sum(feature_diff_time > self.th_slow) 28 | rate = num_slow / len(feature_diff_time) 29 | 30 | exceed_times = rate / self.th_slow_rate 31 | if exceed_times > 1.0: 32 | return True, exceed_times 33 | return False, exceed_times 34 | -------------------------------------------------------------------------------- /robot_mouse_track/risk_motion/motion_vertical_horizontal_linear.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from robot_mouse_track.utils import num_runs 3 | from robot_mouse_track.mouse_track import MouseTrack 4 | 5 | 6 | class VerticalHorizontalLinearMotion: 7 | """ 8 | 横/竖直线运动(人手可能会画出横/竖直线,但是很难画出非常长的横/竖直线) 9 | 10 | :var int default=10 least_point: 这条线上至少有多少个点 11 | :var int default=500 th_length_x: 横向直线运动长度超过多少,认为是风险,单位px 12 | :var int default=500 th_length_y: 纵向直线运动长度超过多少,认为是风险,单位px 13 | """ 14 | 15 | def __init__(self): 16 | self.least_point = 10 17 | 18 | self.th_length_x = 500 19 | self.th_length_y = 500 20 | 21 | def judge_risk(self, mouse_track: MouseTrack): 22 | """ 23 | 风险判定 24 | 25 | :param MouseTrack mouse_track: 鼠标轨迹对象 26 | :return: (have_risk, x_risk_level, y_risk_level) 27 | :rtype: bool, (float, float) 28 | """ 29 | arr_trace_x = mouse_track.arr_trace[:, 0] 30 | arr_trace_y = mouse_track.arr_trace[:, 1] 31 | arr_diff = mouse_track.arr_trace[1:, :-1] - mouse_track.arr_trace[:-1, :-1] 32 | arr_diff_x = arr_diff[:, 0] 33 | arr_diff_y = arr_diff[:, 1] 34 | lst_x_is_0 = num_runs(arr_diff_x) 35 | lst_y_is_0 = num_runs(arr_diff_y) 36 | lst_x_is_0 = [i for i in lst_x_is_0 if i[-1] - i[0] >= self.least_point] 37 | lst_y_is_0 = [i for i in lst_y_is_0 if i[-1] - i[0] >= self.least_point] 38 | 39 | max_length_y = 0 40 | for y_start, y_end in lst_x_is_0: 41 | arr = arr_trace_y[y_start:y_end + 1] 42 | length = np.max(arr) - np.min(arr) 43 | if length > max_length_y: 44 | max_length_y = length 45 | 46 | max_length_x = 0 47 | for x_start, x_end in lst_y_is_0: 48 | arr = arr_trace_x[x_start:x_end + 1] 49 | length = np.max(arr) - np.min(arr) 50 | if length > max_length_x: 51 | max_length_x = length 52 | 53 | exceed_times_x = max_length_x / self.th_length_x 54 | exceed_times_y = max_length_y / self.th_length_y 55 | if exceed_times_x > 1.0 or exceed_times_y > 1.0: 56 | return True, (exceed_times_x, exceed_times_y) 57 | return False, (exceed_times_x, exceed_times_y) 58 | -------------------------------------------------------------------------------- /robot_mouse_track/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def num_runs(arr, num=0): 5 | """ 6 | 获取ndarray中连续为0的开始结束索引,[a, b) 7 | :param arr: 8 | :return: 9 | """ 10 | # Create an array that is 1 where a is 0, and pad each end with an extra 0. 11 | is_zero = np.concatenate(([0], np.equal(arr, num).view(np.int8), [0])) 12 | absdiff = np.abs(np.diff(is_zero)) 13 | # Runs start and end where absdiff is 1. 14 | ranges = np.where(absdiff == 1)[0].reshape(-1, 2) 15 | return ranges 16 | 17 | 18 | def small_runs(arr, span=5): 19 | """ 20 | 获取ndarray中连续变化幅度较小的开始结束索引,[a, b] 21 | :param arr: 22 | :param span: 容差多少度 23 | :return: 24 | """ 25 | # Create an array that is 1 where a is 0, and pad each end with an extra 0. 26 | arr_diff = np.abs(np.diff(arr)) 27 | is_small = np.concatenate(([0], (arr_diff < span).view(np.int8), [0])) 28 | abs_diff = np.abs(np.diff(is_small)) 29 | # Runs start and end where absdiff is 1. 30 | ranges = np.where(abs_diff == 1)[0].reshape(-1, 2) 31 | return ranges 32 | 33 | 34 | # if __name__ == '__main__': 35 | # a = [1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 25, 9, 0, 0, 0, 0, 9, 8, 7, 0, 5, 5] 36 | # runs = num_runs(a, num=0) 37 | # print(runs) 38 | # a = [89.99, 89.98, 90.01, 0, 0, 4, 25.7, 25.6, 25.8, 0, 0, 0, 9, 8, 7, 0, 5, 5] 39 | # # a = [89.8, 89.91, 90.2, 0, 5, 5] 40 | # runs = small_runs(a, span=1) 41 | # print(runs) 42 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from setuptools import find_packages 3 | 4 | # with open("README.rst", "r", encoding="utf-8") as f: 5 | # long_description = f.read() 6 | # python setup.py sdist build 7 | # twine upload dist/* 8 | setup(name='robot_mouse_track', # 包名 9 | version='0.0.6', # 版本号 10 | description='A small example package', 11 | long_description='随着互联网技术的发展,鼠标轨迹识别算法在很多人机交互产品中的需求日益增加,比如,一些网站为了防止被爬,增加了一些滑块验证码,但是一些软件已经可以模拟人的行为破解滑块验证码。本项目就是通过对鼠标轨迹的特征分析,判定是否是人的行为还是机器行为。常见应用场景:网站反爬虫、在线考试系统脚本刷题。', 12 | author='itmorn', 13 | author_email='12567148@qq.com', 14 | url='https://github.com/itmorn/robot-mouse-track', 15 | install_requires=[], 16 | license='Apache License', 17 | # packages=find_packages(), 18 | packages=['robot_mouse_track','robot_mouse_track.risk_motion'], 19 | platforms=["all"], 20 | classifiers=[ 21 | 'Intended Audience :: Developers', 22 | 'Operating System :: OS Independent', 23 | 'Natural Language :: Chinese (Simplified)', 24 | 'Programming Language :: Python :: 3.5', 25 | 'Programming Language :: Python :: 3.6', 26 | 'Programming Language :: Python :: 3.7', 27 | 'Programming Language :: Python :: 3.8', 28 | 'Programming Language :: Python :: 3.9', 29 | 'Topic :: Software Development :: Libraries' 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/tests/__init__.py -------------------------------------------------------------------------------- /tests/risk_motion/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itmorn/robot-mouse-track/29abff3efcbda17867d08a3eacd430a9c2df240a/tests/risk_motion/__init__.py -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_constant_velocity.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:25 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn 7 | from robot_mouse_track import contants 8 | from robot_mouse_track.mouse_track import MouseTrack 9 | from robot_mouse_track.risk_motion.motion_constant_velocity import ConstantVelocityMotion 10 | 11 | def test_judge_risk(): 12 | mouse_track = MouseTrack(trace_itmorn) 13 | 14 | rule_mouse_jump = ConstantVelocityMotion() 15 | rule_mouse_jump.direction=contants.X 16 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 17 | print(flag, exceed_times) 18 | 19 | rule_mouse_jump = ConstantVelocityMotion() 20 | rule_mouse_jump.direction = contants.Y 21 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 22 | print(flag, exceed_times) 23 | 24 | rule_mouse_jump = ConstantVelocityMotion() 25 | rule_mouse_jump.direction = contants.COMBINE 26 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 27 | print(flag, exceed_times) 28 | 29 | rule_mouse_jump = ConstantVelocityMotion() 30 | rule_mouse_jump.direction = "xx" 31 | try: 32 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 33 | except Exception as e: 34 | assert "请输入正确的类型" in e.args[0] 35 | print(flag, exceed_times) 36 | 37 | trace_selenium_jump = [[6, 83, 1655038106398], [6, 84, 1655038107474], [6, 85, 1655038108650], [6, 86, 1655038109698], [6, 87, 1655038110224], [6, 88, 1655038110738]]#, [345, 601, 1655038111263], [365, 601, 1655038111782], [385, 601, 1655038112307], [405, 601, 1655038112831], [425, 601, 1655038113342], [445, 601, 1655038113884], [465, 601, 1655038114396], [485, 601, 1655038114921], [505, 601, 1655038115453], [525, 601, 1655038115973], [545, 601, 1655038116500], [565, 601, 1655038117035], [585, 601, 1655038117566], [605, 601, 1655038118095], [625, 601, 1655038118635], [645, 601, 1655038119177], [15, 721, 1655038120794]] 38 | mouse_track = MouseTrack(trace_selenium_jump) 39 | rule_mouse_jump = ConstantVelocityMotion() 40 | rule_mouse_jump.least_length = 2 41 | rule_mouse_jump.least_point = 2 42 | rule_mouse_jump.direction = contants.COMBINE 43 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 44 | print(flag, exceed_times) 45 | 46 | trace_selenium_jump = [[6, 83, 1655038106398], [6, 84, 1655038107474], [6, 85, 1655038108650], [6, 86, 1655038109698], [6, 87, 1655038110224], [6, 88, 1655038110738]]#, [345, 601, 1655038111263], [365, 601, 1655038111782], [385, 601, 1655038112307], [405, 601, 1655038112831], [425, 601, 1655038113342], [445, 601, 1655038113884], [465, 601, 1655038114396], [485, 601, 1655038114921], [505, 601, 1655038115453], [525, 601, 1655038115973], [545, 601, 1655038116500], [565, 601, 1655038117035], [585, 601, 1655038117566], [605, 601, 1655038118095], [625, 601, 1655038118635], [645, 601, 1655038119177], [15, 721, 1655038120794]] 47 | mouse_track = MouseTrack(trace_selenium_jump) 48 | rule_mouse_jump = ConstantVelocityMotion() 49 | rule_mouse_jump.least_length = 3 50 | rule_mouse_jump.least_point = 3 51 | rule_mouse_jump.direction = contants.COMBINE 52 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 53 | print(flag,exceed_times) 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_jump.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:25 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn 7 | from robot_mouse_track.mouse_track import MouseTrack 8 | from robot_mouse_track.risk_motion.motion_jump import JumpMotion 9 | 10 | 11 | def test_judge_risk(): 12 | mouse_track = MouseTrack(trace_itmorn) 13 | # mouse_track.show_track() 14 | rule_mouse_jump = JumpMotion(th_velocity=20, th_acceleration=1.4) 15 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 16 | print(flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration) 17 | 18 | rule_mouse_jump = JumpMotion(th_velocity=1, th_acceleration=0.1) 19 | flag, (exceed_times_velocity, exceed_times_acceleration) = rule_mouse_jump.judge_risk(mouse_track) 20 | print(flag, "JumpMotion", exceed_times_velocity, exceed_times_acceleration) 21 | -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_linear.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:26 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn 7 | from robot_mouse_track.mouse_track import MouseTrack 8 | from robot_mouse_track.risk_motion.motion_linear import LinearMotion 9 | 10 | 11 | def test_judge_risk(): 12 | mouse_track = MouseTrack(trace_itmorn) 13 | # mouse_track.show_track() 14 | rule_mouse_jump = LinearMotion() 15 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 16 | print(flag, "LinearMotion", exceed_times) 17 | 18 | rule_mouse_jump = LinearMotion() 19 | rule_mouse_jump.least_point = 1 # 这条线上至少有多少个点 20 | rule_mouse_jump.th_length = 1 # 斜线运动长度超过多少,认为是风险,单位px 21 | flag, exceed_times = rule_mouse_jump.judge_risk(mouse_track) 22 | print(flag, "LinearMotion", exceed_times) 23 | -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_similar.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:27 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn, trace_answer_unlock 7 | from robot_mouse_track.mouse_track import MouseTrack 8 | from robot_mouse_track.risk_motion.motion_similar import SimilarMotion, calc_vec 9 | 10 | 11 | def test_judge_risk(): 12 | lst_vec_bank = [] 13 | mouse_track1 = MouseTrack(trace_itmorn) 14 | vec1 = calc_vec(mouse_track1) 15 | lst_vec_bank.append(vec1) 16 | 17 | mouse_track2 = MouseTrack(trace_answer_unlock) 18 | vec_now = calc_vec(mouse_track2) 19 | 20 | rule_mouse = SimilarMotion() 21 | flag, exceed_times = rule_mouse.judge_risk(vec=vec_now, lst_vec_bank=lst_vec_bank) 22 | print(flag, "SimilarMotion", exceed_times) 23 | 24 | rule_mouse = SimilarMotion() 25 | flag, exceed_times = rule_mouse.judge_risk(vec=vec1, lst_vec_bank=lst_vec_bank) 26 | print(flag, "SimilarMotion", exceed_times) 27 | -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_slow.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:27 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn 7 | from robot_mouse_track.mouse_track import MouseTrack 8 | from robot_mouse_track.risk_motion.motion_slow import SlowMotion 9 | 10 | 11 | def test_judge_risk(): 12 | mouse_track = MouseTrack(trace_itmorn) 13 | # mouse_track.show_track() 14 | 15 | rule_mouse = SlowMotion() 16 | flag, exceed_times = rule_mouse.judge_risk(mouse_track) 17 | print(flag, "SlowMotion", exceed_times) 18 | 19 | rule_mouse = SlowMotion() 20 | rule_mouse.th_slow=5 21 | flag, exceed_times = rule_mouse.judge_risk(mouse_track) 22 | print(flag, "SlowMotion", exceed_times) 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/risk_motion/test_motion_vertical_horizontal_linear.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/13-20:27 4 | @Email: 12567148@qq.com 5 | """ 6 | from examples.trace_examples import trace_itmorn 7 | from robot_mouse_track.mouse_track import MouseTrack 8 | from robot_mouse_track.risk_motion.motion_vertical_horizontal_linear import VerticalHorizontalLinearMotion 9 | 10 | 11 | def test_judge_risk(): 12 | mouse_track = MouseTrack(trace_itmorn) 13 | rule_mouse_jump = VerticalHorizontalLinearMotion() 14 | flag, (exceed_times_x, exceed_times_y) = rule_mouse_jump.judge_risk(mouse_track) 15 | print(flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y) 16 | 17 | rule_mouse_jump = VerticalHorizontalLinearMotion() 18 | rule_mouse_jump.least_point = 1 19 | 20 | rule_mouse_jump.th_length_x = 1 21 | rule_mouse_jump.th_length_y = 1 22 | flag, (exceed_times_x, exceed_times_y) = rule_mouse_jump.judge_risk(mouse_track) 23 | print(flag, "VerticalHorizontalLinearMotion", exceed_times_x, exceed_times_y) 24 | -------------------------------------------------------------------------------- /tests/test_mouse_track.py: -------------------------------------------------------------------------------- 1 | """ 2 | @Auth: itmorn 3 | @Date: 2022/6/11-16:52 4 | @Email: 12567148@qq.com 5 | """ 6 | from robot_mouse_track import contants 7 | from examples.trace_examples import trace_itmorn 8 | from robot_mouse_track.mouse_track import MouseTrack 9 | import numpy as np 10 | 11 | def test_get_feature_diff_time(): 12 | ma = MouseTrack(trace_itmorn) 13 | feature_diff_time = ma.get_feature_diff_time() 14 | feature_diff_time = ma.get_feature_diff_time() 15 | 16 | assert isinstance(feature_diff_time, np.ndarray) 17 | 18 | 19 | def test_get_feature_dev(): 20 | ma = MouseTrack(trace_itmorn) 21 | feature_diff_time = ma.get_feature_dev() 22 | 23 | assert isinstance(feature_diff_time, list) 24 | 25 | ma = MouseTrack(trace_itmorn) 26 | feature_diff_time = ma.get_feature_dev(order=1,mode=contants.DECOMPOSITION) 27 | feature_diff_time = ma.get_feature_dev(order=2,mode=contants.DECOMPOSITION) 28 | feature_diff_time = ma.get_feature_dev(order=2,mode=contants.DECOMPOSITION) 29 | print() 30 | 31 | assert isinstance(feature_diff_time, list) 32 | 33 | try: 34 | feature_diff_time = ma.get_feature_dev(order=2, mode="xxx") 35 | except Exception as e: 36 | assert "请输入正确的类型" in e.args[0] 37 | 38 | 39 | 40 | def test_show_track(): 41 | ma = MouseTrack(trace_itmorn) 42 | ma.show_track() 43 | 44 | 45 | def test_get_feature_doa(): 46 | ma = MouseTrack(trace_itmorn) 47 | feature_doa = ma.get_feature_doa() 48 | feature_doa = ma.get_feature_doa() 49 | 50 | assert isinstance(feature_doa, np.ndarray) 51 | --------------------------------------------------------------------------------