├── .gitignore ├── FuncNav.php ├── LICENSE ├── README.md ├── README_zh.md ├── composer.json ├── composer.lock ├── favicon.ico ├── img ├── home.png ├── index.png └── source.png ├── index.html ├── index.php ├── static ├── css │ └── app.7468d54c44137433a4eabefeea754ff4.css └── js │ ├── app.654b05895887cf3afe7a.js │ ├── manifest.3dff49ac782c8e4820fb.js │ └── vendor.695f7660217c2e2b3e8b.js └── webui ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .postcssrc.js ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package-lock.json ├── package.json ├── src ├── App.vue ├── Bus.js ├── assets │ └── logo.png ├── components │ ├── BreakpointNav.vue │ ├── FileNav.vue │ ├── FuncNav.vue │ ├── Home.vue │ ├── Index.vue │ ├── PopupList.vue │ ├── Source.vue │ ├── TracesNav.vue │ └── wiki │ │ ├── WikiEn.vue │ │ └── WikiZh.vue ├── main.js └── router │ └── index.js ├── static └── .gitkeep └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.un~ 3 | vendor 4 | node_modules 5 | dist/ 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | -------------------------------------------------------------------------------- /FuncNav.php: -------------------------------------------------------------------------------- 1 | namespace = $node->name; 21 | return; 22 | } 23 | 24 | if ($node instanceof Class_) { 25 | $this->class = empty($this->namespace) ? $node->name 26 | : $this->namespace . '\\' . $node->name; 27 | return; 28 | } 29 | 30 | if ($node instanceof Function_) { 31 | $params = []; 32 | foreach ($node->params as $param) { 33 | if ($param->byRef) { 34 | $params[] = '&' . $param->name; 35 | } else { 36 | $params[] = $param->name; 37 | } 38 | } 39 | $this->popupList[] = [ 40 | 'type' => 'func', 41 | 'name' => $node->name, 42 | 'params' => implode(", ", $params), 43 | 'line' => $node->getLine() 44 | ]; 45 | return; 46 | } 47 | 48 | if ($node instanceof ClassMethod) { 49 | $params = []; 50 | foreach ($node->params as $param) { 51 | if ($param->byRef) { 52 | $params[] = '&' . $param->name; 53 | } else { 54 | $params[] = $param->name; 55 | } 56 | } 57 | $this->popupList[] = [ 58 | 'type' => 'method', 59 | 'class' => $this->class, 60 | 'name' => $node->name, 61 | 'params' => implode(", ", $params), 62 | 'line' => $node->getLine() 63 | ]; 64 | } 65 | } 66 | 67 | public function leaveNode(Node $node) 68 | { 69 | if ($node instanceof Namespace_) { 70 | $this->namespace = ''; 71 | return; 72 | } 73 | 74 | if ($node instanceof Class_) { 75 | $this->class = ''; 76 | } 77 | } 78 | 79 | public function getPopupList() 80 | { 81 | return $this->popupList; 82 | } 83 | }; 84 | 85 | function get_funcNav() 86 | { 87 | $popupList = []; 88 | $filename = $_GET['file']; 89 | if (file_exists($filename)) { 90 | $code = file_get_contents($filename); 91 | if (!empty($code)) { 92 | $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); 93 | try { 94 | $ast = $parser->parse($code); 95 | } catch (Error $error) { 96 | header('HTTP/1.0 500 Internal Server Error'); 97 | echo "Parse error: {$error->getMessage()}"; 98 | return; 99 | } 100 | $funcNav = new FuncNav(); 101 | $traverser = new NodeTraverser(); 102 | $traverser->addVisitor($funcNav); 103 | $traverser->traverse($ast); 104 | $popupList = $funcNav->getPopupList(); 105 | } 106 | } 107 | header('content-type: application/json'); 108 | echo json_encode($popupList); 109 | } 110 | -------------------------------------------------------------------------------- /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 | [中文README](README_zh.md) 2 | 3 | This is a web ui for [ytrace](https://github.com/yangxikun/ytrace), see also [ytrace_chrome_extension](https://github.com/yangxikun/ytrace_chrome_extension). 4 | 5 | ## Why 6 | I need to take over some project. To understand the code logic, I have to debug the code(many code is dirty but run:-)). I can use var_dump/die(this is inefficient) or the powerful debug tool XDebug(but traces and remote debugging still not so convenient). 7 | 8 | So, I create this tool, make traces combined with step-through debugging. Hope it useful for you. 9 | 10 | ## feature 11 | * step through debugging 12 | * break point 13 | * jump to any executed source code line 14 | * step back through your step history 15 | 16 | ![](img/index.png) 17 | 18 | ![](img/home.png) 19 | 20 | ![](img/source.png) 21 | 22 | ## Install 23 | * git clone this project 24 | * composer install 25 | * in project root dir, run `php -S localhost:8088` 26 | 27 | > By default, ytrace_gui will detect ytrace.output_dir from ini_get. If need, you can edit `index.php`, change `//define('YTRACE_OUTPUT_DIR', '/tmp/ytrace/');` 28 | 29 | ## Wiki 30 | __Home Page__: List all traced files, click on one of the items in the list to open source page. 31 | + Clear Traces: delete all traced files. 32 | + Refresh: update list. 33 | + List field explanation: 34 | - Sapi: cli, fpm-fcgi etc 35 | - Method: http method in fpm-fcgi 36 | - Uri: http request uri in fpm-fcgi 37 | - File: file name 38 | - Size: file size 39 | - Time: created time 40 | 41 | __Source Page__: show detail of traced files. 42 | + source code show in left side, traced value show in right side. 43 | - only assignment and function call will be traced 44 | - ++, --, +=, /=, -=, *=, %= etc, shows the values before these operators execute 45 | - PHP 7 cannot show internal function parameters name (parameter name cannot be found will be showed as $...) 46 | + executed line will be highlight in green, dark green means current execute 47 | - click highlighted line number, can jump current execute to it 48 | - ctrl+click line number, can set/clear a breakpoint (breakpoint will be highlight in red line number) 49 | + execute operation: 50 | - step into: same with gdb 51 | - step back: execute back through your step history 52 | - step over: same with gdb 53 | - step out: same with gdb 54 | - continue: same with gdb, execute to next breakpoint 55 | - reset: reset execute to first entry 56 | + shortcut: 57 | - ctrl+o: open 10 latest traced file popup list 58 | - ctrl+p: open traced source file popup list, only available in source page 59 | - ctrl+r: open current source file function/method popup list, only available in source page 60 | - ctrl+b: open breakpoints popup list, only available in source page 61 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | 本项目为 [ytrace](https://github.com/yangxikun/ytrace)提供了web ui界面,对应的还有[ytrace_chrome_extension](https://github.com/yangxikun/ytrace_chrome_extension). 2 | 3 | ## 背景 4 | 工作上,有时会需要接手一些旧项目或者熟悉新项目。为了理解项目中的代码逻辑,我们需要不断的调试代码(大部分代码都是dirty but run:-)),通常的调试方式是var_dump/die(低效的),或者使用Xdebug的跟踪、单步调试功能,但觉得这些方式还是不够方便。 5 | 6 | 于是,开发了这个工具,将跟踪和单步调试结合起来,目前用起来还挺方便的,希望也对你有用。 7 | 8 | ## 特性 9 | * 单步调试 10 | * 断点 11 | * 跳转到任意执行过的代码行 12 | * 根据单步历史,往回单步执行 13 | 14 | ![](img/index.png) 15 | 16 | ![](img/home.png) 17 | 18 | ![](img/source.png) 19 | 20 | ## 安装 21 | * git clone 当前项目 22 | * composer install 23 | * 在项目的根目录,执行`php -S localhost:8088` 24 | 25 | > 默认的,ytrace_gui会通过ini_get获取ytrace.output_dir的值。如果需要的话,你可以通过编辑`index.php`,修改`//define('YTRACE_OUTPUT_DIR', '/tmp/ytrace/');`,以设置ytrace的输出目录。 26 | 27 | ## Wiki 28 | __Home 页面__: 列出所有的跟踪文件, 通过点击列表中的某行记录打开Source 页面。 29 | + Clear Traces: 删除所有的跟踪文件。 30 | + Refresh: 刷新列表。 31 | + 列表字段说明: 32 | - Sapi: cli, fpm-fcgi 等 33 | - Method: fpm-fcgi中的http 请求方法 34 | - Uri: fpm-fcgi中的http 请求路径及参数 35 | - File: 跟踪文件名 36 | - Size: 跟踪文件大小 37 | - Time: 跟踪文件创建时间 38 | 39 | __Source Page__: 显示跟踪内容详情。 40 | + 左边模块显示源码文件,右边模块显示跟踪到的变量值。 41 | - 只跟踪赋值和函数调用 42 | - ++、--、+=、/=、-=、*=、%=等,显示的值是这些运算符执行之前的值 43 | - PHP 7无法获取到扩展函数的参数名称(无法显示参数名称的会显示为$...) 44 | + 被执行过的代码行,行号会以绿色高亮出来,深绿色表示当前执行所在的行 45 | - 点击高亮的行号,可以将执行跳转至对应行 46 | - ctrl+点击行号,可以设置或取消断点(断点的行号会以红色高亮) 47 | + 执行操作: 48 | - step into: 同gdb 49 | - step back: 根据你的执行历史,往回执行 50 | - step over: 同gdb 51 | - step out: 同gdb 52 | - continue: 同gdb,执行到下一个断点 53 | - reset:重置执行过程 54 | + 快捷键: 55 | - ctrl+o: 打开最新10个跟踪文件的列表浮框 56 | - ctrl+p: 打开被跟踪到的源码文件的列表浮框,只能在Source 页面使用 57 | - ctrl+r: 打开当前显示的源码文件函数/方法的列表浮框,只能在Source 页面使用 58 | - ctrl+b: 打开断点列表浮框,只能在Source 页面使用 59 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "nikic/fast-route": "^1.2", 4 | "nikic/php-parser": "3.1.*" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "b53a49287c1526c6d43bc82b7070bed2", 8 | "packages": [ 9 | { 10 | "name": "nikic/fast-route", 11 | "version": "v1.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/nikic/FastRoute.git", 15 | "reference": "b5f95749071c82a8e0f58586987627054400cdf6" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/b5f95749071c82a8e0f58586987627054400cdf6", 20 | "reference": "b5f95749071c82a8e0f58586987627054400cdf6", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.4.0" 25 | }, 26 | "type": "library", 27 | "autoload": { 28 | "psr-4": { 29 | "FastRoute\\": "src/" 30 | }, 31 | "files": [ 32 | "src/functions.php" 33 | ] 34 | }, 35 | "notification-url": "https://packagist.org/downloads/", 36 | "license": [ 37 | "BSD-3-Clause" 38 | ], 39 | "authors": [ 40 | { 41 | "name": "Nikita Popov", 42 | "email": "nikic@php.net" 43 | } 44 | ], 45 | "description": "Fast request router for PHP", 46 | "keywords": [ 47 | "router", 48 | "routing" 49 | ], 50 | "time": "2017-01-19T11:35:12+00:00" 51 | }, 52 | { 53 | "name": "nikic/php-parser", 54 | "version": "v3.1.2", 55 | "source": { 56 | "type": "git", 57 | "url": "https://github.com/nikic/PHP-Parser.git", 58 | "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89" 59 | }, 60 | "dist": { 61 | "type": "zip", 62 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08131e7ff29de6bb9f12275c7d35df71f25f4d89", 63 | "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89", 64 | "shasum": "" 65 | }, 66 | "require": { 67 | "ext-tokenizer": "*", 68 | "php": ">=5.5" 69 | }, 70 | "require-dev": { 71 | "phpunit/phpunit": "~4.0|~5.0" 72 | }, 73 | "bin": [ 74 | "bin/php-parse" 75 | ], 76 | "type": "library", 77 | "extra": { 78 | "branch-alias": { 79 | "dev-master": "3.0-dev" 80 | } 81 | }, 82 | "autoload": { 83 | "psr-4": { 84 | "PhpParser\\": "lib/PhpParser" 85 | } 86 | }, 87 | "notification-url": "https://packagist.org/downloads/", 88 | "license": [ 89 | "BSD-3-Clause" 90 | ], 91 | "authors": [ 92 | { 93 | "name": "Nikita Popov" 94 | } 95 | ], 96 | "description": "A PHP parser written in PHP", 97 | "keywords": [ 98 | "parser", 99 | "php" 100 | ], 101 | "time": "2017-11-04T11:48:34+00:00" 102 | } 103 | ], 104 | "packages-dev": [], 105 | "aliases": [], 106 | "minimum-stability": "stable", 107 | "stability-flags": [], 108 | "prefer-stable": false, 109 | "prefer-lowest": false, 110 | "platform": [], 111 | "platform-dev": [] 112 | } 113 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/favicon.ico -------------------------------------------------------------------------------- /img/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/img/home.png -------------------------------------------------------------------------------- /img/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/img/index.png -------------------------------------------------------------------------------- /img/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/img/source.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | ytrace_gui
-------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | addRoute('GET', '/trace', 'get_all_trace'); 22 | $r->addRoute('DELETE', '/trace', 'clear_trace'); 23 | $r->addRoute('GET', '/trace/{id:.+}', 'get_trace'); 24 | $r->addRoute('GET', '/source', 'get_source'); 25 | $r->addRoute('GET', '/file-nav/{id:.+}', 'get_fileNav'); 26 | $r->addRoute('GET', '/func-nav', 'get_funcNav'); 27 | $r->addRoute('GET', '/', 'index'); 28 | }); 29 | 30 | // Fetch method and URI from somewhere 31 | $httpMethod = $_SERVER['REQUEST_METHOD']; 32 | $uri = $_SERVER['REQUEST_URI']; 33 | 34 | // Strip query string (?foo=bar) and decode URI 35 | if (false !== $pos = strpos($uri, '?')) { 36 | $uri = substr($uri, 0, $pos); 37 | } 38 | $uri = rawurldecode($uri); 39 | 40 | $routeInfo = $dispatcher->dispatch($httpMethod, $uri); 41 | switch ($routeInfo[0]) { 42 | case FastRoute\Dispatcher::NOT_FOUND: 43 | // ... 404 Not Found 44 | break; 45 | case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: 46 | $allowedMethods = $routeInfo[1]; 47 | // ... 405 Method Not Allowed 48 | break; 49 | case FastRoute\Dispatcher::FOUND: 50 | $handler = $routeInfo[1]; 51 | $vars = $routeInfo[2]; 52 | // ... call $handler with $vars 53 | call_user_func($handler, $vars); 54 | break; 55 | } 56 | 57 | function index() 58 | { 59 | readfile('index.html'); 60 | } 61 | 62 | function get_all_trace() 63 | { 64 | if (!is_dir(YTRACE_OUTPUT_DIR)) { 65 | header("HTTP/1.0 500 Internal Server Error"); 66 | echo YTRACE_OUTPUT_DIR . " does not exists."; 67 | return; 68 | } 69 | $res = []; 70 | $files = scandir(YTRACE_OUTPUT_DIR); 71 | foreach ($files as $file) { 72 | $pathinfo = pathinfo($file); 73 | if (isset($pathinfo['extension']) && $pathinfo['extension'] == 'yt') { 74 | $handle = fopen(YTRACE_OUTPUT_DIR . $file, 'r'); 75 | $info = explode("\t", rtrim(fgets($handle), "\n")); 76 | $fileSize = filesize(YTRACE_OUTPUT_DIR . $file); 77 | switch (true) { 78 | case $fileSize > 1024 *1024: 79 | $fileSize = round($fileSize / (1024*1024), 2) . 'M'; 80 | break; 81 | case $fileSize > 1024: 82 | $fileSize = round($fileSize / 1024, 2) . 'k'; 83 | break; 84 | } 85 | $item = [ 86 | 'sapi' => $info[0], 'file' => $pathinfo['filename'], 87 | 'time' => date('Y-m-d H:i:s', filectime(YTRACE_OUTPUT_DIR . $file)), 88 | 'size' => $fileSize 89 | ]; 90 | if ($info[0] == "fpm-fcgi") { 91 | $item['method'] = $info[1]; 92 | $item['uri'] = $info[2]; 93 | } 94 | $res[] = $item; 95 | } 96 | } 97 | usort($res, function ($a, $b) { 98 | return $a['time'] < $b['time'] ? 1 : -1; 99 | }); 100 | header('content-type: application/json'); 101 | echo json_encode($res); 102 | } 103 | 104 | function get_trace($input) 105 | { 106 | $filename = YTRACE_OUTPUT_DIR . $input['id'] . '.yt'; 107 | if (file_exists($filename)) { 108 | readfile($filename); 109 | } else { 110 | header("HTTP/1.0 404 Not Found"); 111 | } 112 | } 113 | 114 | function get_source() 115 | { 116 | $filename = $_GET['file']; 117 | if (file_exists($filename)) { 118 | readfile($filename); 119 | } else { 120 | header("HTTP/1.0 404 Not Found"); 121 | } 122 | } 123 | 124 | function clear_trace() 125 | { 126 | $files = scandir(YTRACE_OUTPUT_DIR); 127 | foreach ($files as $file) { 128 | $pathinfo = pathinfo($file); 129 | if ($pathinfo['extension'] == 'yt') { 130 | unlink(YTRACE_OUTPUT_DIR . $file); 131 | } 132 | } 133 | } 134 | 135 | function get_fileNav($input) 136 | { 137 | $filename = YTRACE_OUTPUT_DIR . $input['id'] . '.yt'; 138 | if (file_exists($filename)) { 139 | $f = fopen($filename, "r"); 140 | $first = true; 141 | $trace_files = []; 142 | while (true) { 143 | $line = fgets($f); 144 | if ($line === false) break; 145 | if ($first) { 146 | $first = false; 147 | continue; 148 | } 149 | $line = explode("\t", $line); 150 | $trace_files[$line[0]] = null; 151 | } 152 | header('content-type: application/json'); 153 | echo json_encode(array_keys($trace_files)); 154 | } else { 155 | header("HTTP/1.0 404 Not Found"); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /static/js/app.654b05895887cf3afe7a.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{"/E90":function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("b-list-group",{staticStyle:{"max-height":"35rem","overflow-y":"scroll"}},e._l(e.showItems,function(t,a){return r("b-list-group-item",{key:a,class:{active:a===e.select},on:{click:function(r){e.rowClicked(t.line)}}},[e._v("\n "+e._s(t.prototype)+"\n ")])}))},n=[],i={render:a,staticRenderFns:n};t.a=i},"10oB":function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"container",staticStyle:{"margin-top":"4rem"}},[r("h1",{staticStyle:{"text-align":"center"}},[e._v("Welcome to Ytrace"),r("h5",{staticStyle:{display:"inline-block"}},[r("b-badge",{attrs:{pill:"",variant:"secondary"}},[e._v("alpha")])],1)]),e._v(" "),r("p",{staticStyle:{"text-align":"center"}},[e._v("This is wiki page for Ytrace's gui, chrome extension, php extension.")]),e._v(" "),r("div",[r("b-card",{attrs:{title:"GUI"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.GUI}})],1)]),e._v(" "),r("b-card",{attrs:{title:"Chrome Extension"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.ChromeExtension}})],1)]),e._v(" "),r("b-card",{attrs:{title:"PHP Extension"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.PHPExtension}})],1)])],1)])},n=[],i={render:a,staticRenderFns:n};t.a=i},"1Bj8":function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("table",{staticClass:"table"},[r("tbody",e._l(e.showFiles,function(t,a){return r("tr",{class:{"table-active":a===e.select},on:{click:function(r){e.rowClicked(t)}}},[r("td",[e._v(e._s(t.sapi))]),e._v(" "),r("td",[e._v(e._s(t.method))]),e._v(" "),r("td",{staticClass:"uri"},[e._v(e._s(t.uri))]),e._v(" "),r("td",[e._v(e._s(t.file))]),e._v(" "),r("td",[e._v(e._s(t.size))]),e._v(" "),r("td",[e._v(e._s(t.time))])])}))])},n=[],i={render:a,staticRenderFns:n};t.a=i},"21zj":function(e,t){},"240R":function(e,t,r){"use strict";var a=r("7+uW");t.a=new a.a({data:function(){return{curSourceFile:""}}})},"42Hy":function(e,t,r){"use strict";function a(e){r("qE0+")}var n=r("DK6z"),i=r("9Ju6"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-a79ba2ce",null);t.a=l.exports},"4fNz":function(e,t){e.exports={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"⁡",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"⁡",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅",in:"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺",int:"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"}},"5abi":function(e,t){},"68IZ":function(e,t,r){"use strict";var a=r("mvHQ"),n=r.n(a),i=r("kX7f"),o=r.n(i),s=r("EzsT"),l=(r.n(s),r("eKfU")),c=(r.n(l),r("V71o")),u=r.n(c),h=r("0XFg").sprintf;t.a={name:"Trace-Source",components:{vueLoading:u.a},data:function(){return{loading:!0,initOk:!1,id:"",sourceEditor:null,varEditor:null,file:"",line:0,type:"",level:0,items:[],fileCoverage:{},step:-1,stepHistory:[],codeHeight:0}},watch:{"$route.params.id":function(e){void 0!==e&&""!==this.id&&this.id!==e&&(this.id=e,this.fetchTrace())}},mounted:function(){var e=this,t=document.body,r=document.documentElement,a=Math.max(t.scrollHeight,t.offsetHeight,r.clientHeight,r.scrollHeight,r.offsetHeight);this.codeHeight=a-document.getElementById("head").clientHeight-44,this.sourceEditor=this.initEditor(this.$refs.code,!0),delete this.sourceEditor.keyBinding.$defaultHandler.commandKeyBinding["ctrl-p"],this.sourceEditor.renderer.on("afterRender",function(){var t=e.$refs.code.querySelector("div.ace_gutter-layer").childNodes,r=e.fileCoverage[e.$bus.curSourceFile],a=e.$localStorage.get(e.$bus.curSourceFile);a&&(a=JSON.parse(a));for(var n=0;n=0&&r.stepInto(r.step,s)}},!1),a},fetchTrace:function(){var e=this;this.loading=!0,this.id=this.$route.params.id,this.$http.get("/trace/"+encodeURI(this.id)).then(function(t){var r=t.data.trimRight().split("\n"),a=[],n={};delete r[0];var i={},o=-1;for(var s in r){var l=r[s].split("\t");if(l[3]=Number(l[3]),"F"===l[2]&&(l[5]=Number(l[5])),a.push(l),n[l[0]]||(n[l[0]]={}),n[l[0]][l[1]]||(n[l[0]][l[1]]=Number(s)-1),-1===o){if(!i[l[0]]){var c=e.$localStorage.get(l[0]);c&&(c=JSON.parse(c),i[l[0]]=c)}i[l[0]]&&i[l[0]][l[1]]&&(o=s-1)}}e.items=a,e.fileCoverage=n,e.loading=!1,-1===o&&(o=0),e.reset(o)})},stripslashes:function(e){return(e+"").replace(/\\./g,function(e){return new Function('return "'+e+'"')()||e})},stepInto:function(e,t){var r=this.items[t];if(r)switch(e>=0&&this.stepHistory.push(e),this.step=t,this.line=Number(r[1]),this.type=r[2],this.level=r[3],r[0]!==this.file?(this.file=r[0],this.loadFile()):this.file!==this.$bus.curSourceFile?this.loadFile():this.sourceEditor.gotoLine(this.line),this.type){case"A":this.varEditor.setValue("0&&this.stepInto(-1,this.stepHistory.pop())},_continue:function(){for(var e=this.step+1,t=this.items[e],r={};t;){if(!r[t[0]]){var a=this.$localStorage.get(t[0]);a&&(a=JSON.parse(a),r[t[0]]=a)}if(r[t[0]]&&r[t[0]][t[1]])return void this.stepInto(this.step,e);e++,t=this.items[e]}},reset:function(e){this.file="",this.line=0,this.type="",this.level=0,this.stepHistory=[],this.step=e,this.stepInto(-1,this.step)},loadFile:function(){var e=this;this.$bus.curSourceFile=this.file,this.$http.get("/source?file="+encodeURI(this.file)).then(function(t){var r=e.sourceEditor;r.setValue(t.data),r.gotoLine(e.line)})},justLoadFile:function(e,t){var r=this;this.$bus.curSourceFile=e,this.$http.get("/source?file="+encodeURI(e)).then(function(e){var a=r.sourceEditor;a.setValue(e.data),t?a.gotoLine(t):a.navigateFileEnd()})}}}},"9Ju6":function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",[r("div",[r("b-button",{attrs:{disabled:"en"==e.wiki,size:"sm",variant:"outline-secondary"},on:{click:function(t){e.wiki="en"}}},[e._v("EN")]),e._v(" "),r("b-button",{attrs:{disabled:"zh"==e.wiki,size:"sm",variant:"outline-secondary"},on:{click:function(t){e.wiki="zh"}}},[e._v("ZH")])],1),e._v(" "),r("wiki-en",{directives:[{name:"show",rawName:"v-show",value:"en"==e.wiki,expression:"wiki == 'en'"}]}),e._v(" "),r("wiki-zh",{directives:[{name:"show",rawName:"v-show",value:"zh"==e.wiki,expression:"wiki == 'zh'"}]})],1)},n=[],i={render:a,staticRenderFns:n};t.a=i},"9M+g":function(e,t){},D4uH:function(e,t,r){"use strict";function a(e){r("cCV5")}var n=r("dXrS"),i=r("Txe8"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,null,null);t.a=l.exports},DK6z:function(e,t,r){"use strict";var a=r("XDsQ"),n=r("EuIC");t.a={components:{WikiEn:a.a,WikiZh:n.a},data:function(){return{wiki:"en"}}}},DUku:function(e,t){},EuIC:function(e,t,r){"use strict";function a(e){r("chry")}var n=r("ejnp"),i=r("Nf+p"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-22a91784",null);t.a=l.exports},Fs8J:function(e,t,r){"use strict";t.a={name:"Home",data:function(){return{files:[],fields:[{key:"sapi",sortable:!0},{key:"method",sortable:!0},{key:"uri",sortable:!0,tdClass:"uri"},{key:"file",sortable:!0},{key:"size",sortable:!1},{key:"time",sortable:!0}]}},mounted:function(){this.fetchTraces()},methods:{rowClicked:function(e,t,r){this.$router.push({name:"Source",params:{id:e.file}})},fetchTraces:function(){var e=this;this.$http.get("/trace").then(function(t){e.files=t.data})},clearTraces:function(){var e=this;this.$http.delete("/trace").then(function(t){e.fetchTraces()}),this.$bus.$emit("clearTraces")}}}},HCoV:function(e,t){},Icg2:function(e,t){},Jltp:function(e,t,r){"use strict";var a=r("Wq+S"),n=r("UtXa"),i=r("fWJJ"),o=r("lzLh");t.a={components:{TracesNav:a.a,FuncNav:n.a,FileNav:i.a,BreakpointNav:o.a},data:function(){return{search:"",type:"",select:0,enter:!1,showLen:0}},mounted:function(){var e=this;document.onkeydown=function(t){if("Escape"===t.key)return e.type="",void(e.enter=!1);switch(!0){case"o"===t.key&&t.ctrlKey:t.preventDefault(),e.search="",e.select=0,e.type="traces-nav",e.enter=!1,e.$refs.popupList.show();break;case"r"===t.key&&t.ctrlKey&&"Source"===e.$route.name:t.preventDefault(),e.search="",e.select=0,e.type="func-nav",e.enter=!1,e.$refs.popupList.show();break;case"p"===t.key&&t.ctrlKey&&"Source"===e.$route.name:t.preventDefault(),e.search="",e.select=0,e.type="file-nav",e.enter=!1,e.$refs.popupList.show();break;case"b"===t.key&&t.ctrlKey&&"Source"===e.$route.name:t.preventDefault(),e.search="",e.select=0,e.type="breakpoint-nav",e.enter=!1,e.$refs.popupList.show();break;case e.$refs.popupList.is_show&&"ArrowDown"===t.key&&e.showLen>1:e.select===e.showLen-1?e.select=0:e.select+=1;break;case e.$refs.popupList.is_show&&"ArrowUp"===t.key&&e.showLen>1:0===e.select?e.select=e.showLen-1:e.select-=1;break;case e.$refs.popupList.is_show&&"Enter"===t.key&&e.showLen>0:e.enter=!0}}},methods:{searchInputFocus:function(){this.$refs.searchInput.focus()},updateShowLen:function(e){this.showLen=e},close:function(){this.type="",this.enter=!1,this.$refs.popupList.hide()}}}},Jmt5:function(e,t){},K5QJ:function(e,t,r){"use strict";t.a={props:{search:String,select:Number,enter:Boolean},data:function(){return{files:[],showFiles:[]}},mounted:function(){this.fetchTraceFiles()},watch:{search:function(e){var t=[];for(var r in this.files)this.files[r].uri&&this.files[r].uri.indexOf(e)>=0?t.push(this.files[r]):this.files[r].file.indexOf(e)>=0&&t.push(this.files[r]);this.showFiles=t,this.$emit("updateShowLen",this.showFiles.length)},enter:function(e){e&&(this.$emit("close"),this.$router.push({name:"Source",params:{id:this.showFiles[this.select].file}}))}},methods:{fetchTraceFiles:function(){var e=this;this.$http.get("/trace").then(function(t){e.search="",e.files=t.data.slice(0,10),e.showFiles=e.files,e.$emit("updateShowLen",e.showFiles.length)})},rowClicked:function(e){this.$emit("close"),this.$router.push({name:"Source",params:{id:e.file}})}}}},M93x:function(e,t,r){"use strict";function a(e){r("21zj")}var n=r("xJD8"),i=r("hpS7"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-025d5711",null);t.a=l.exports},NHnr:function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=r("7+uW"),n=r("M93x"),i=r("YaEn"),o=r("mtWM"),s=r.n(o),l=r("sCSS"),c=r("240R"),u=r("UnSZ"),h=r.n(u),_=r("Xoog"),p=r.n(_),d=r("Jmt5"),m=(r.n(d),r("9M+g")),g=(r.n(m),r("nZeE"),r("D4uH"));a.a.component("icon",g.a),a.a.component("VueMarkdown",p.a),a.a.use(h.a),a.a.use(l.a),a.a.prototype.$http=s.a,a.a.prototype.$bus=c.a,a.a.config.productionTip=!1,new a.a({el:"#app",router:i.a,template:"",components:{App:n.a}})},"Nf+p":function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"container",staticStyle:{"margin-top":"4rem"}},[r("h1",{staticStyle:{"text-align":"center"}},[e._v("欢迎使用 Ytrace"),r("h5",{staticStyle:{display:"inline-block"}},[r("b-badge",{attrs:{pill:"",variant:"secondary"}},[e._v("alpha")])],1)]),e._v(" "),r("p",{staticStyle:{"text-align":"center"}},[e._v("这是个包含Ytrace的gui、chrome扩展、php扩展相关Wiki的页面")]),e._v(" "),r("div",[r("b-card",{attrs:{title:"GUI"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.GUI}})],1)]),e._v(" "),r("b-card",{attrs:{title:"Chrome 扩展"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.ChromeExtension}})],1)]),e._v(" "),r("b-card",{attrs:{title:"PHP 扩展"}},[r("div",{staticClass:"card-text"},[r("vue-markdown",{attrs:{source:e.PHPExtension}})],1)])],1)])},n=[],i={render:a,staticRenderFns:n};t.a=i},OUSy:function(e,t){},RQcw:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("b-list-group",{staticStyle:{"max-height":"35rem"}},e._l(e.showItems,function(t,a){return r("b-list-group-item",{key:a,class:{active:a===e.select},on:{click:function(r){e.rowClicked(t)}}},[e._v("\n "+e._s(t)+"\n ")])}))},n=[],i={render:a,staticRenderFns:n};t.a=i},RWjT:function(e,t){e.exports={100:"💯",1234:"🔢",grinning:"😀",smiley:"😃",smile:"😄",grin:"😁",laughing:"😆",satisfied:"😆",sweat_smile:"😅",joy:"😂",rofl:"🤣",relaxed:"☺️",blush:"😊",innocent:"😇",slightly_smiling_face:"🙂",upside_down_face:"🙃",wink:"😉",relieved:"😌",heart_eyes:"😍",kissing_heart:"😘",kissing:"😗",kissing_smiling_eyes:"😙",kissing_closed_eyes:"😚",yum:"😋",stuck_out_tongue_winking_eye:"😜",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue:"😛",money_mouth_face:"🤑",hugs:"🤗",nerd_face:"🤓",sunglasses:"😎",clown_face:"🤡",cowboy_hat_face:"🤠",smirk:"😏",unamused:"😒",disappointed:"😞",pensive:"😔",worried:"😟",confused:"😕",slightly_frowning_face:"🙁",frowning_face:"☹️",persevere:"😣",confounded:"😖",tired_face:"😫",weary:"😩",triumph:"😤",angry:"😠",rage:"😡",pout:"😡",no_mouth:"😶",neutral_face:"😐",expressionless:"😑",hushed:"😯",frowning:"😦",anguished:"😧",open_mouth:"😮",astonished:"😲",dizzy_face:"😵",flushed:"😳",scream:"😱",fearful:"😨",cold_sweat:"😰",cry:"😢",disappointed_relieved:"😥",drooling_face:"🤤",sob:"😭",sweat:"😓",sleepy:"😪",sleeping:"😴",roll_eyes:"🙄",thinking:"🤔",lying_face:"🤥",grimacing:"😬",zipper_mouth_face:"🤐",nauseated_face:"🤢",sneezing_face:"🤧",mask:"😷",face_with_thermometer:"🤒",face_with_head_bandage:"🤕",smiling_imp:"😈",imp:"👿",japanese_ogre:"👹",japanese_goblin:"👺",hankey:"💩",poop:"💩",shit:"💩",ghost:"👻",skull:"💀",skull_and_crossbones:"☠️",alien:"👽",space_invader:"👾",robot:"🤖",jack_o_lantern:"🎃",smiley_cat:"😺",smile_cat:"😸",joy_cat:"😹",heart_eyes_cat:"😻",smirk_cat:"😼",kissing_cat:"😽",scream_cat:"🙀",crying_cat_face:"😿",pouting_cat:"😾",open_hands:"👐",raised_hands:"🙌",clap:"👏",pray:"🙏",handshake:"🤝","+1":"👍",thumbsup:"👍","-1":"👎",thumbsdown:"👎",fist_oncoming:"👊",facepunch:"👊",punch:"👊",fist_raised:"✊",fist:"✊",fist_left:"🤛",fist_right:"🤜",crossed_fingers:"🤞",v:"✌️",metal:"🤘",ok_hand:"👌",point_left:"👈",point_right:"👉",point_up_2:"👆",point_down:"👇",point_up:"☝️",hand:"✋",raised_hand:"✋",raised_back_of_hand:"🤚",raised_hand_with_fingers_splayed:"🖐",vulcan_salute:"🖖",wave:"👋",call_me_hand:"🤙",muscle:"💪",middle_finger:"🖕",fu:"🖕",writing_hand:"✍️",selfie:"🤳",nail_care:"💅",ring:"💍",lipstick:"💄",kiss:"💋",lips:"👄",tongue:"👅",ear:"👂",nose:"👃",footprints:"👣",eye:"👁",eyes:"👀",speaking_head:"🗣",bust_in_silhouette:"👤",busts_in_silhouette:"👥",baby:"👶",boy:"👦",girl:"👧",man:"👨",woman:"👩",blonde_woman:"👱‍♀",blonde_man:"👱",person_with_blond_hair:"👱",older_man:"👴",older_woman:"👵",man_with_gua_pi_mao:"👲",woman_with_turban:"👳‍♀",man_with_turban:"👳",policewoman:"👮‍♀",policeman:"👮",cop:"👮",construction_worker_woman:"👷‍♀",construction_worker_man:"👷",construction_worker:"👷",guardswoman:"💂‍♀",guardsman:"💂",female_detective:"🕵️‍♀️",male_detective:"🕵",detective:"🕵",woman_health_worker:"👩‍⚕",man_health_worker:"👨‍⚕",woman_farmer:"👩‍🌾",man_farmer:"👨‍🌾",woman_cook:"👩‍🍳",man_cook:"👨‍🍳",woman_student:"👩‍🎓",man_student:"👨‍🎓",woman_singer:"👩‍🎤",man_singer:"👨‍🎤",woman_teacher:"👩‍🏫",man_teacher:"👨‍🏫",woman_factory_worker:"👩‍🏭",man_factory_worker:"👨‍🏭",woman_technologist:"👩‍💻",man_technologist:"👨‍💻",woman_office_worker:"👩‍💼",man_office_worker:"👨‍💼",woman_mechanic:"👩‍🔧",man_mechanic:"👨‍🔧",woman_scientist:"👩‍🔬",man_scientist:"👨‍🔬",woman_artist:"👩‍🎨",man_artist:"👨‍🎨",woman_firefighter:"👩‍🚒",man_firefighter:"👨‍🚒",woman_pilot:"👩‍✈",man_pilot:"👨‍✈",woman_astronaut:"👩‍🚀",man_astronaut:"👨‍🚀",woman_judge:"👩‍⚖",man_judge:"👨‍⚖",mrs_claus:"🤶",santa:"🎅",princess:"👸",prince:"🤴",bride_with_veil:"👰",man_in_tuxedo:"🤵",angel:"👼",pregnant_woman:"🤰",bowing_woman:"🙇‍♀",bowing_man:"🙇",bow:"🙇",tipping_hand_woman:"💁",information_desk_person:"💁",sassy_woman:"💁",tipping_hand_man:"💁‍♂",sassy_man:"💁‍♂",no_good_woman:"🙅",no_good:"🙅",ng_woman:"🙅",no_good_man:"🙅‍♂",ng_man:"🙅‍♂",ok_woman:"🙆",ok_man:"🙆‍♂",raising_hand_woman:"🙋",raising_hand:"🙋",raising_hand_man:"🙋‍♂",woman_facepalming:"🤦‍♀",man_facepalming:"🤦‍♂",woman_shrugging:"🤷‍♀",man_shrugging:"🤷‍♂",pouting_woman:"🙎",person_with_pouting_face:"🙎",pouting_man:"🙎‍♂",frowning_woman:"🙍",person_frowning:"🙍",frowning_man:"🙍‍♂",haircut_woman:"💇",haircut:"💇",haircut_man:"💇‍♂",massage_woman:"💆",massage:"💆",massage_man:"💆‍♂",business_suit_levitating:"🕴",dancer:"💃",man_dancing:"🕺",dancing_women:"👯",dancers:"👯",dancing_men:"👯‍♂",walking_woman:"🚶‍♀",walking_man:"🚶",walking:"🚶",running_woman:"🏃‍♀",running_man:"🏃",runner:"🏃",running:"🏃",couple:"👫",two_women_holding_hands:"👭",two_men_holding_hands:"👬",couple_with_heart_woman_man:"💑",couple_with_heart:"💑",couple_with_heart_woman_woman:"👩‍❤️‍👩",couple_with_heart_man_man:"👨‍❤️‍👨",couplekiss_man_woman:"💏",couplekiss_woman_woman:"👩‍❤️‍💋‍👩",couplekiss_man_man:"👨‍❤️‍💋‍👨",family_man_woman_boy:"👪",family:"👪",family_man_woman_girl:"👨‍👩‍👧",family_man_woman_girl_boy:"👨‍👩‍👧‍👦",family_man_woman_boy_boy:"👨‍👩‍👦‍👦",family_man_woman_girl_girl:"👨‍👩‍👧‍👧",family_woman_woman_boy:"👩‍👩‍👦",family_woman_woman_girl:"👩‍👩‍👧",family_woman_woman_girl_boy:"👩‍👩‍👧‍👦",family_woman_woman_boy_boy:"👩‍👩‍👦‍👦",family_woman_woman_girl_girl:"👩‍👩‍👧‍👧",family_man_man_boy:"👨‍👨‍👦",family_man_man_girl:"👨‍👨‍👧",family_man_man_girl_boy:"👨‍👨‍👧‍👦",family_man_man_boy_boy:"👨‍👨‍👦‍👦",family_man_man_girl_girl:"👨‍👨‍👧‍👧",family_woman_boy:"👩‍👦",family_woman_girl:"👩‍👧",family_woman_girl_boy:"👩‍👧‍👦",family_woman_boy_boy:"👩‍👦‍👦",family_woman_girl_girl:"👩‍👧‍👧",family_man_boy:"👨‍👦",family_man_girl:"👨‍👧",family_man_girl_boy:"👨‍👧‍👦",family_man_boy_boy:"👨‍👦‍👦",family_man_girl_girl:"👨‍👧‍👧",womans_clothes:"👚",shirt:"👕",tshirt:"👕",jeans:"👖",necktie:"👔",dress:"👗",bikini:"👙",kimono:"👘",high_heel:"👠",sandal:"👡",boot:"👢",mans_shoe:"👞",shoe:"👞",athletic_shoe:"👟",womans_hat:"👒",tophat:"🎩",mortar_board:"🎓",crown:"👑",rescue_worker_helmet:"⛑",school_satchel:"🎒",pouch:"👝",purse:"👛",handbag:"👜",briefcase:"💼",eyeglasses:"👓",dark_sunglasses:"🕶",closed_umbrella:"🌂",open_umbrella:"☂️",dog:"🐶",cat:"🐱",mouse:"🐭",hamster:"🐹",rabbit:"🐰",fox_face:"🦊",bear:"🐻",panda_face:"🐼",koala:"🐨",tiger:"🐯",lion:"🦁",cow:"🐮",pig:"🐷",pig_nose:"🐽",frog:"🐸",monkey_face:"🐵",see_no_evil:"🙈",hear_no_evil:"🙉",speak_no_evil:"🙊",monkey:"🐒",chicken:"🐔",penguin:"🐧",bird:"🐦",baby_chick:"🐤",hatching_chick:"🐣",hatched_chick:"🐥",duck:"🦆",eagle:"🦅",owl:"🦉",bat:"🦇",wolf:"🐺",boar:"🐗",horse:"🐴",unicorn:"🦄",bee:"🐝",honeybee:"🐝",bug:"🐛",butterfly:"🦋",snail:"🐌",shell:"🐚",beetle:"🐞",ant:"🐜",spider:"🕷",spider_web:"🕸",turtle:"🐢",snake:"🐍",lizard:"🦎",scorpion:"🦂",crab:"🦀",squid:"🦑",octopus:"🐙",shrimp:"🦐",tropical_fish:"🐠",fish:"🐟",blowfish:"🐡",dolphin:"🐬",flipper:"🐬",shark:"🦈",whale:"🐳",whale2:"🐋",crocodile:"🐊",leopard:"🐆",tiger2:"🐅",water_buffalo:"🐃",ox:"🐂",cow2:"🐄",deer:"🦌",dromedary_camel:"🐪",camel:"🐫",elephant:"🐘",rhinoceros:"🦏",gorilla:"🦍",racehorse:"🐎",pig2:"🐖",goat:"🐐",ram:"🐏",sheep:"🐑",dog2:"🐕",poodle:"🐩",cat2:"🐈",rooster:"🐓",turkey:"🦃",dove:"🕊",rabbit2:"🐇",mouse2:"🐁",rat:"🐀",chipmunk:"🐿",feet:"🐾",paw_prints:"🐾",dragon:"🐉",dragon_face:"🐲",cactus:"🌵",christmas_tree:"🎄",evergreen_tree:"🌲",deciduous_tree:"🌳",palm_tree:"🌴",seedling:"🌱",herb:"🌿",shamrock:"☘️",four_leaf_clover:"🍀",bamboo:"🎍",tanabata_tree:"🎋",leaves:"🍃",fallen_leaf:"🍂",maple_leaf:"🍁",mushroom:"🍄",ear_of_rice:"🌾",bouquet:"💐",tulip:"🌷",rose:"🌹",wilted_flower:"🥀",sunflower:"🌻",blossom:"🌼",cherry_blossom:"🌸",hibiscus:"🌺",earth_americas:"🌎",earth_africa:"🌍",earth_asia:"🌏",full_moon:"🌕",waning_gibbous_moon:"🌖",last_quarter_moon:"🌗",waning_crescent_moon:"🌘",new_moon:"🌑",waxing_crescent_moon:"🌒",first_quarter_moon:"🌓",moon:"🌔",waxing_gibbous_moon:"🌔",new_moon_with_face:"🌚",full_moon_with_face:"🌝",sun_with_face:"🌞",first_quarter_moon_with_face:"🌛",last_quarter_moon_with_face:"🌜",crescent_moon:"🌙",dizzy:"💫",star:"⭐️",star2:"🌟",sparkles:"✨",zap:"⚡️",fire:"🔥",boom:"💥",collision:"💥",comet:"☄",sunny:"☀️",sun_behind_small_cloud:"🌤",partly_sunny:"⛅️",sun_behind_large_cloud:"🌥",sun_behind_rain_cloud:"🌦",rainbow:"🌈",cloud:"☁️",cloud_with_rain:"🌧",cloud_with_lightning_and_rain:"⛈",cloud_with_lightning:"🌩",cloud_with_snow:"🌨",snowman_with_snow:"☃️",snowman:"⛄️",snowflake:"❄️",wind_face:"🌬",dash:"💨",tornado:"🌪",fog:"🌫",ocean:"🌊",droplet:"💧",sweat_drops:"💦",umbrella:"☔️",green_apple:"🍏",apple:"🍎",pear:"🍐",tangerine:"🍊",orange:"🍊",mandarin:"🍊",lemon:"🍋",banana:"🍌",watermelon:"🍉",grapes:"🍇",strawberry:"🍓",melon:"🍈",cherries:"🍒",peach:"🍑",pineapple:"🍍",kiwi_fruit:"🥝",avocado:"🥑",tomato:"🍅",eggplant:"🍆",cucumber:"🥒",carrot:"🥕",corn:"🌽",hot_pepper:"🌶",potato:"🥔",sweet_potato:"🍠",chestnut:"🌰",peanuts:"🥜",honey_pot:"🍯",croissant:"🥐",bread:"🍞",baguette_bread:"🥖",cheese:"🧀",egg:"🥚",fried_egg:"🍳",bacon:"🥓",pancakes:"🥞",fried_shrimp:"🍤",poultry_leg:"🍗",meat_on_bone:"🍖",pizza:"🍕",hotdog:"🌭",hamburger:"🍔",fries:"🍟",stuffed_flatbread:"🥙",taco:"🌮",burrito:"🌯",green_salad:"🥗",shallow_pan_of_food:"🥘",spaghetti:"🍝",ramen:"🍜",stew:"🍲",fish_cake:"🍥",sushi:"🍣",bento:"🍱",curry:"🍛",rice:"🍚",rice_ball:"🍙",rice_cracker:"🍘",oden:"🍢",dango:"🍡",shaved_ice:"🍧",ice_cream:"🍨",icecream:"🍦",cake:"🍰",birthday:"🎂",custard:"🍮",lollipop:"🍭",candy:"🍬",chocolate_bar:"🍫",popcorn:"🍿",doughnut:"🍩",cookie:"🍪",milk_glass:"🥛",baby_bottle:"🍼",coffee:"☕️",tea:"🍵",sake:"🍶",beer:"🍺",beers:"🍻",clinking_glasses:"🥂",wine_glass:"🍷",tumbler_glass:"🥃",cocktail:"🍸",tropical_drink:"🍹",champagne:"🍾",spoon:"🥄",fork_and_knife:"🍴",plate_with_cutlery:"🍽",soccer:"⚽️",basketball:"🏀",football:"🏈",baseball:"⚾️",tennis:"🎾",volleyball:"🏐",rugby_football:"🏉","8ball":"🎱",ping_pong:"🏓",badminton:"🏸",goal_net:"🥅",ice_hockey:"🏒",field_hockey:"🏑",cricket:"🏏",golf:"⛳️",bow_and_arrow:"🏹",fishing_pole_and_fish:"🎣",boxing_glove:"🥊",martial_arts_uniform:"🥋",ice_skate:"⛸",ski:"🎿",skier:"⛷",snowboarder:"🏂",weight_lifting_woman:"🏋️‍♀️",weight_lifting_man:"🏋",person_fencing:"🤺",women_wrestling:"🤼‍♀",men_wrestling:"🤼‍♂",woman_cartwheeling:"🤸‍♀",man_cartwheeling:"🤸‍♂",basketball_woman:"⛹️‍♀️",basketball_man:"⛹",woman_playing_handball:"🤾‍♀",man_playing_handball:"🤾‍♂",golfing_woman:"🏌️‍♀️",golfing_man:"🏌",surfing_woman:"🏄‍♀",surfing_man:"🏄",surfer:"🏄",swimming_woman:"🏊‍♀",swimming_man:"🏊",swimmer:"🏊",woman_playing_water_polo:"🤽‍♀",man_playing_water_polo:"🤽‍♂",rowing_woman:"🚣‍♀",rowing_man:"🚣",rowboat:"🚣",horse_racing:"🏇",biking_woman:"🚴‍♀",biking_man:"🚴",bicyclist:"🚴",mountain_biking_woman:"🚵‍♀",mountain_biking_man:"🚵",mountain_bicyclist:"🚵",running_shirt_with_sash:"🎽",medal_sports:"🏅",medal_military:"🎖","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉",trophy:"🏆",rosette:"🏵",reminder_ribbon:"🎗",ticket:"🎫",tickets:"🎟",circus_tent:"🎪",woman_juggling:"🤹‍♀",man_juggling:"🤹‍♂",performing_arts:"🎭",art:"🎨",clapper:"🎬",microphone:"🎤",headphones:"🎧",musical_score:"🎼",musical_keyboard:"🎹",drum:"🥁",saxophone:"🎷",trumpet:"🎺",guitar:"🎸",violin:"🎻",game_die:"🎲",dart:"🎯",bowling:"🎳",video_game:"🎮",slot_machine:"🎰",car:"🚗",red_car:"🚗",taxi:"🚕",blue_car:"🚙",bus:"🚌",trolleybus:"🚎",racing_car:"🏎",police_car:"🚓",ambulance:"🚑",fire_engine:"🚒",minibus:"🚐",truck:"🚚",articulated_lorry:"🚛",tractor:"🚜",kick_scooter:"🛴",bike:"🚲",motor_scooter:"🛵",motorcycle:"🏍",rotating_light:"🚨",oncoming_police_car:"🚔",oncoming_bus:"🚍",oncoming_automobile:"🚘",oncoming_taxi:"🚖",aerial_tramway:"🚡",mountain_cableway:"🚠",suspension_railway:"🚟",railway_car:"🚃",train:"🚋",mountain_railway:"🚞",monorail:"🚝",bullettrain_side:"🚄",bullettrain_front:"🚅",light_rail:"🚈",steam_locomotive:"🚂",train2:"🚆",metro:"🚇",tram:"🚊",station:"🚉",helicopter:"🚁",small_airplane:"🛩",airplane:"✈️",flight_departure:"🛫",flight_arrival:"🛬",rocket:"🚀",artificial_satellite:"🛰",seat:"💺",canoe:"🛶",boat:"⛵️",sailboat:"⛵️",motor_boat:"🛥",speedboat:"🚤",passenger_ship:"🛳",ferry:"⛴",ship:"🚢",anchor:"⚓️",construction:"🚧",fuelpump:"⛽️",busstop:"🚏",vertical_traffic_light:"🚦",traffic_light:"🚥",world_map:"🗺",moyai:"🗿",statue_of_liberty:"🗽",fountain:"⛲️",tokyo_tower:"🗼",european_castle:"🏰",japanese_castle:"🏯",stadium:"🏟",ferris_wheel:"🎡",roller_coaster:"🎢",carousel_horse:"🎠",parasol_on_ground:"⛱",beach_umbrella:"🏖",desert_island:"🏝",mountain:"⛰",mountain_snow:"🏔",mount_fuji:"🗻",volcano:"🌋",desert:"🏜",camping:"🏕",tent:"⛺️",railway_track:"🛤",motorway:"🛣",building_construction:"🏗",factory:"🏭",house:"🏠",house_with_garden:"🏡",houses:"🏘",derelict_house:"🏚",office:"🏢",department_store:"🏬",post_office:"🏣",european_post_office:"🏤",hospital:"🏥",bank:"🏦",hotel:"🏨",convenience_store:"🏪",school:"🏫",love_hotel:"🏩",wedding:"💒",classical_building:"🏛",church:"⛪️",mosque:"🕌",synagogue:"🕍",kaaba:"🕋",shinto_shrine:"⛩",japan:"🗾",rice_scene:"🎑",national_park:"🏞",sunrise:"🌅",sunrise_over_mountains:"🌄",stars:"🌠",sparkler:"🎇",fireworks:"🎆",city_sunrise:"🌇",city_sunset:"🌆",cityscape:"🏙",night_with_stars:"🌃",milky_way:"🌌",bridge_at_night:"🌉",foggy:"🌁",watch:"⌚️",iphone:"📱",calling:"📲",computer:"💻",keyboard:"⌨️",desktop_computer:"🖥",printer:"🖨",computer_mouse:"🖱",trackball:"🖲",joystick:"🕹",clamp:"🗜",minidisc:"💽",floppy_disk:"💾",cd:"💿",dvd:"📀",vhs:"📼",camera:"📷",camera_flash:"📸",video_camera:"📹",movie_camera:"🎥",film_projector:"📽",film_strip:"🎞",telephone_receiver:"📞",phone:"☎️",telephone:"☎️",pager:"📟",fax:"📠",tv:"📺",radio:"📻",studio_microphone:"🎙",level_slider:"🎚",control_knobs:"🎛",stopwatch:"⏱",timer_clock:"⏲",alarm_clock:"⏰",mantelpiece_clock:"🕰",hourglass:"⌛️",hourglass_flowing_sand:"⏳",satellite:"📡",battery:"🔋",electric_plug:"🔌",bulb:"💡",flashlight:"🔦",candle:"🕯",wastebasket:"🗑",oil_drum:"🛢",money_with_wings:"💸",dollar:"💵",yen:"💴",euro:"💶",pound:"💷",moneybag:"💰",credit_card:"💳",gem:"💎",balance_scale:"⚖️",wrench:"🔧",hammer:"🔨",hammer_and_pick:"⚒",hammer_and_wrench:"🛠",pick:"⛏",nut_and_bolt:"🔩",gear:"⚙️",chains:"⛓",gun:"🔫",bomb:"💣",hocho:"🔪",knife:"🔪",dagger:"🗡",crossed_swords:"⚔️",shield:"🛡",smoking:"🚬",coffin:"⚰️",funeral_urn:"⚱️",amphora:"🏺",crystal_ball:"🔮",prayer_beads:"📿",barber:"💈",alembic:"⚗️",telescope:"🔭",microscope:"🔬",hole:"🕳",pill:"💊",syringe:"💉",thermometer:"🌡",toilet:"🚽",potable_water:"🚰",shower:"🚿",bathtub:"🛁",bath:"🛀",bellhop_bell:"🛎",key:"🔑",old_key:"🗝",door:"🚪",couch_and_lamp:"🛋",bed:"🛏",sleeping_bed:"🛌",framed_picture:"🖼",shopping:"🛍",shopping_cart:"🛒",gift:"🎁",balloon:"🎈",flags:"🎏",ribbon:"🎀",confetti_ball:"🎊",tada:"🎉",dolls:"🎎",izakaya_lantern:"🏮",lantern:"🏮",wind_chime:"🎐",email:"✉️",envelope:"✉️",envelope_with_arrow:"📩",incoming_envelope:"📨","e-mail":"📧",love_letter:"💌",inbox_tray:"📥",outbox_tray:"📤",package:"📦",label:"🏷",mailbox_closed:"📪",mailbox:"📫",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",postbox:"📮",postal_horn:"📯",scroll:"📜",page_with_curl:"📃",page_facing_up:"📄",bookmark_tabs:"📑",bar_chart:"📊",chart_with_upwards_trend:"📈",chart_with_downwards_trend:"📉",spiral_notepad:"🗒",spiral_calendar:"🗓",calendar:"📆",date:"📅",card_index:"📇",card_file_box:"🗃",ballot_box:"🗳",file_cabinet:"🗄",clipboard:"📋",file_folder:"📁",open_file_folder:"📂",card_index_dividers:"🗂",newspaper_roll:"🗞",newspaper:"📰",notebook:"📓",notebook_with_decorative_cover:"📔",ledger:"📒",closed_book:"📕",green_book:"📗",blue_book:"📘",orange_book:"📙",books:"📚",book:"📖",open_book:"📖",bookmark:"🔖",link:"🔗",paperclip:"📎",paperclips:"🖇",triangular_ruler:"📐",straight_ruler:"📏",pushpin:"📌",round_pushpin:"📍",scissors:"✂️",pen:"🖊",fountain_pen:"🖋",black_nib:"✒️",paintbrush:"🖌",crayon:"🖍",memo:"📝",pencil:"📝",pencil2:"✏️",mag:"🔍",mag_right:"🔎",lock_with_ink_pen:"🔏",closed_lock_with_key:"🔐",lock:"🔒",unlock:"🔓",heart:"❤️",yellow_heart:"💛",green_heart:"💚",blue_heart:"💙",purple_heart:"💜",black_heart:"🖤",broken_heart:"💔",heavy_heart_exclamation:"❣️",two_hearts:"💕",revolving_hearts:"💞",heartbeat:"💓",heartpulse:"💗",sparkling_heart:"💖",cupid:"💘",gift_heart:"💝",heart_decoration:"💟",peace_symbol:"☮️",latin_cross:"✝️",star_and_crescent:"☪️",om:"🕉",wheel_of_dharma:"☸️",star_of_david:"✡️",six_pointed_star:"🔯",menorah:"🕎",yin_yang:"☯️",orthodox_cross:"☦️",place_of_worship:"🛐",ophiuchus:"⛎",aries:"♈️",taurus:"♉️",gemini:"♊️",cancer:"♋️",leo:"♌️",virgo:"♍️",libra:"♎️",scorpius:"♏️",sagittarius:"♐️",capricorn:"♑️",aquarius:"♒️",pisces:"♓️",id:"🆔",atom_symbol:"⚛️",accept:"🉑",radioactive:"☢️",biohazard:"☣️",mobile_phone_off:"📴",vibration_mode:"📳",eight_pointed_black_star:"✴️",vs:"🆚",white_flower:"💮",ideograph_advantage:"🉐",secret:"㊙️",congratulations:"㊗️",u6e80:"🈵",a:"🅰️",b:"🅱️",ab:"🆎",cl:"🆑",o2:"🅾️",sos:"🆘",x:"❌",o:"⭕️",stop_sign:"🛑",no_entry:"⛔️",name_badge:"📛",no_entry_sign:"🚫",anger:"💢",hotsprings:"♨️",no_pedestrians:"🚷",do_not_litter:"🚯",no_bicycles:"🚳","non-potable_water":"🚱",underage:"🔞",no_mobile_phones:"📵",no_smoking:"🚭",exclamation:"❗️",heavy_exclamation_mark:"❗️",grey_exclamation:"❕",question:"❓",grey_question:"❔",bangbang:"‼️",interrobang:"⁉️",low_brightness:"🔅",high_brightness:"🔆",part_alternation_mark:"〽️",warning:"⚠️",children_crossing:"🚸",trident:"🔱",fleur_de_lis:"⚜️",beginner:"🔰",recycle:"♻️",white_check_mark:"✅",chart:"💹",sparkle:"❇️",eight_spoked_asterisk:"✳️",negative_squared_cross_mark:"❎",globe_with_meridians:"🌐",diamond_shape_with_a_dot_inside:"💠",m:"Ⓜ️",cyclone:"🌀",zzz:"💤",atm:"🏧",wc:"🚾",wheelchair:"♿️",parking:"🅿️",sa:"🈂️",passport_control:"🛂",customs:"🛃",baggage_claim:"🛄",left_luggage:"🛅",mens:"🚹",womens:"🚺",baby_symbol:"🚼",restroom:"🚻",put_litter_in_its_place:"🚮",cinema:"🎦",signal_strength:"📶",koko:"🈁",symbols:"🔣",information_source:"ℹ️",abc:"🔤",abcd:"🔡",capital_abcd:"🔠",ng:"🆖",ok:"🆗",up:"🆙",cool:"🆒",new:"🆕",free:"🆓",zero:"0️⃣",one:"1️⃣",two:"2️⃣",three:"3️⃣",four:"4️⃣",five:"5️⃣",six:"6️⃣",seven:"7️⃣",eight:"8️⃣",nine:"9️⃣",keycap_ten:"🔟",hash:"#️⃣",asterisk:"*️⃣",arrow_forward:"▶️",pause_button:"⏸",play_or_pause_button:"⏯",stop_button:"⏹",record_button:"⏺",next_track_button:"⏭",previous_track_button:"⏮",fast_forward:"⏩",rewind:"⏪",arrow_double_up:"⏫",arrow_double_down:"⏬",arrow_backward:"◀️",arrow_up_small:"🔼",arrow_down_small:"🔽",arrow_right:"➡️",arrow_left:"⬅️",arrow_up:"⬆️",arrow_down:"⬇️",arrow_upper_right:"↗️",arrow_lower_right:"↘️",arrow_lower_left:"↙️",arrow_upper_left:"↖️",arrow_up_down:"↕️",left_right_arrow:"↔️",arrow_right_hook:"↪️",leftwards_arrow_with_hook:"↩️",arrow_heading_up:"⤴️",arrow_heading_down:"⤵️",twisted_rightwards_arrows:"🔀",repeat:"🔁",repeat_one:"🔂",arrows_counterclockwise:"🔄",arrows_clockwise:"🔃",musical_note:"🎵",notes:"🎶",heavy_plus_sign:"➕",heavy_minus_sign:"➖",heavy_division_sign:"➗",heavy_multiplication_x:"✖️",heavy_dollar_sign:"💲",currency_exchange:"💱",tm:"™️",copyright:"©️",registered:"®️",wavy_dash:"〰️",curly_loop:"➰",loop:"➿",end:"🔚",back:"🔙",on:"🔛",top:"🔝",soon:"🔜",heavy_check_mark:"✔️",ballot_box_with_check:"☑️",radio_button:"🔘",white_circle:"⚪️",black_circle:"⚫️",red_circle:"🔴",large_blue_circle:"🔵",small_red_triangle:"🔺",small_red_triangle_down:"🔻",small_orange_diamond:"🔸",small_blue_diamond:"🔹",large_orange_diamond:"🔶",large_blue_diamond:"🔷",white_square_button:"🔳",black_square_button:"🔲",black_small_square:"▪️",white_small_square:"▫️",black_medium_small_square:"◾️",white_medium_small_square:"◽️",black_medium_square:"◼️",white_medium_square:"◻️",black_large_square:"⬛️",white_large_square:"⬜️",speaker:"🔈",mute:"🔇",sound:"🔉",loud_sound:"🔊",bell:"🔔",no_bell:"🔕",mega:"📣",loudspeaker:"📢",eye_speech_bubble:"👁‍🗨",speech_balloon:"💬",thought_balloon:"💭",right_anger_bubble:"🗯",spades:"♠️",clubs:"♣️",hearts:"♥️",diamonds:"♦️",black_joker:"🃏",flower_playing_cards:"🎴",mahjong:"🀄️",clock1:"🕐",clock2:"🕑",clock3:"🕒",clock4:"🕓",clock5:"🕔",clock6:"🕕",clock7:"🕖",clock8:"🕗",clock9:"🕘",clock10:"🕙",clock11:"🕚",clock12:"🕛",clock130:"🕜",clock230:"🕝",clock330:"🕞",clock430:"🕟",clock530:"🕠",clock630:"🕡",clock730:"🕢",clock830:"🕣",clock930:"🕤",clock1030:"🕥",clock1130:"🕦",clock1230:"🕧",white_flag:"🏳️",black_flag:"🏴",checkered_flag:"🏁",triangular_flag_on_post:"🚩",rainbow_flag:"🏳️‍🌈",afghanistan:"🇦🇫",aland_islands:"🇦🇽",albania:"🇦🇱",algeria:"🇩🇿",american_samoa:"🇦🇸",andorra:"🇦🇩",angola:"🇦🇴",anguilla:"🇦🇮",antarctica:"🇦🇶",antigua_barbuda:"🇦🇬",argentina:"🇦🇷",armenia:"🇦🇲",aruba:"🇦🇼",australia:"🇦🇺",austria:"🇦🇹",azerbaijan:"🇦🇿",bahamas:"🇧🇸",bahrain:"🇧🇭",bangladesh:"🇧🇩",barbados:"🇧🇧",belarus:"🇧🇾",belgium:"🇧🇪",belize:"🇧🇿",benin:"🇧🇯",bermuda:"🇧🇲",bhutan:"🇧🇹",bolivia:"🇧🇴",caribbean_netherlands:"🇧🇶",bosnia_herzegovina:"🇧🇦",botswana:"🇧🇼",brazil:"🇧🇷",british_indian_ocean_territory:"🇮🇴",british_virgin_islands:"🇻🇬",brunei:"🇧🇳",bulgaria:"🇧🇬",burkina_faso:"🇧🇫",burundi:"🇧🇮",cape_verde:"🇨🇻",cambodia:"🇰🇭",cameroon:"🇨🇲",canada:"🇨🇦",canary_islands:"🇮🇨",cayman_islands:"🇰🇾",central_african_republic:"🇨🇫",chad:"🇹🇩",chile:"🇨🇱",cn:"🇨🇳",christmas_island:"🇨🇽",cocos_islands:"🇨🇨",colombia:"🇨🇴",comoros:"🇰🇲",congo_brazzaville:"🇨🇬",congo_kinshasa:"🇨🇩",cook_islands:"🇨🇰",costa_rica:"🇨🇷",cote_divoire:"🇨🇮",croatia:"🇭🇷",cuba:"🇨🇺",curacao:"🇨🇼",cyprus:"🇨🇾",czech_republic:"🇨🇿",denmark:"🇩🇰",djibouti:"🇩🇯",dominica:"🇩🇲",dominican_republic:"🇩🇴",ecuador:"🇪🇨",egypt:"🇪🇬",el_salvador:"🇸🇻",equatorial_guinea:"🇬🇶",eritrea:"🇪🇷",estonia:"🇪🇪",ethiopia:"🇪🇹",eu:"🇪🇺",european_union:"🇪🇺",falkland_islands:"🇫🇰",faroe_islands:"🇫🇴",fiji:"🇫🇯",finland:"🇫🇮",fr:"🇫🇷",french_guiana:"🇬🇫",french_polynesia:"🇵🇫",french_southern_territories:"🇹🇫",gabon:"🇬🇦",gambia:"🇬🇲",georgia:"🇬🇪",de:"🇩🇪",ghana:"🇬🇭",gibraltar:"🇬🇮",greece:"🇬🇷",greenland:"🇬🇱",grenada:"🇬🇩",guadeloupe:"🇬🇵",guam:"🇬🇺",guatemala:"🇬🇹",guernsey:"🇬🇬",guinea:"🇬🇳",guinea_bissau:"🇬🇼",guyana:"🇬🇾",haiti:"🇭🇹",honduras:"🇭🇳",hong_kong:"🇭🇰",hungary:"🇭🇺",iceland:"🇮🇸",india:"🇮🇳",indonesia:"🇮🇩",iran:"🇮🇷",iraq:"🇮🇶",ireland:"🇮🇪",isle_of_man:"🇮🇲",israel:"🇮🇱",it:"🇮🇹",jamaica:"🇯🇲",jp:"🇯🇵",crossed_flags:"🎌",jersey:"🇯🇪",jordan:"🇯🇴",kazakhstan:"🇰🇿",kenya:"🇰🇪",kiribati:"🇰🇮",kosovo:"🇽🇰",kuwait:"🇰🇼",kyrgyzstan:"🇰🇬",laos:"🇱🇦",latvia:"🇱🇻",lebanon:"🇱🇧",lesotho:"🇱🇸",liberia:"🇱🇷",libya:"🇱🇾",liechtenstein:"🇱🇮",lithuania:"🇱🇹",luxembourg:"🇱🇺",macau:"🇲🇴",macedonia:"🇲🇰",madagascar:"🇲🇬",malawi:"🇲🇼",malaysia:"🇲🇾",maldives:"🇲🇻",mali:"🇲🇱",malta:"🇲🇹",marshall_islands:"🇲🇭",martinique:"🇲🇶",mauritania:"🇲🇷",mauritius:"🇲🇺",mayotte:"🇾🇹",mexico:"🇲🇽",micronesia:"🇫🇲",moldova:"🇲🇩",monaco:"🇲🇨",mongolia:"🇲🇳",montenegro:"🇲🇪",montserrat:"🇲🇸",morocco:"🇲🇦",mozambique:"🇲🇿",myanmar:"🇲🇲",namibia:"🇳🇦",nauru:"🇳🇷",nepal:"🇳🇵",netherlands:"🇳🇱",new_caledonia:"🇳🇨",new_zealand:"🇳🇿",nicaragua:"🇳🇮",niger:"🇳🇪",nigeria:"🇳🇬",niue:"🇳🇺",norfolk_island:"🇳🇫",northern_mariana_islands:"🇲🇵",north_korea:"🇰🇵",norway:"🇳🇴",oman:"🇴🇲",pakistan:"🇵🇰",palau:"🇵🇼",palestinian_territories:"🇵🇸",panama:"🇵🇦",papua_new_guinea:"🇵🇬",paraguay:"🇵🇾",peru:"🇵🇪",philippines:"🇵🇭",pitcairn_islands:"🇵🇳",poland:"🇵🇱",portugal:"🇵🇹",puerto_rico:"🇵🇷",qatar:"🇶🇦",reunion:"🇷🇪",romania:"🇷🇴",ru:"🇷🇺",rwanda:"🇷🇼",st_barthelemy:"🇧🇱",st_helena:"🇸🇭",st_kitts_nevis:"🇰🇳",st_lucia:"🇱🇨",st_pierre_miquelon:"🇵🇲",st_vincent_grenadines:"🇻🇨",samoa:"🇼🇸",san_marino:"🇸🇲",sao_tome_principe:"🇸🇹",saudi_arabia:"🇸🇦",senegal:"🇸🇳",serbia:"🇷🇸",seychelles:"🇸🇨",sierra_leone:"🇸🇱",singapore:"🇸🇬",sint_maarten:"🇸🇽",slovakia:"🇸🇰",slovenia:"🇸🇮",solomon_islands:"🇸🇧",somalia:"🇸🇴",south_africa:"🇿🇦",south_georgia_south_sandwich_islands:"🇬🇸",kr:"🇰🇷",south_sudan:"🇸🇸",es:"🇪🇸",sri_lanka:"🇱🇰",sudan:"🇸🇩",suriname:"🇸🇷",swaziland:"🇸🇿",sweden:"🇸🇪",switzerland:"🇨🇭",syria:"🇸🇾",taiwan:"🇹🇼",tajikistan:"🇹🇯",tanzania:"🇹🇿",thailand:"🇹🇭",timor_leste:"🇹🇱",togo:"🇹🇬",tokelau:"🇹🇰",tonga:"🇹🇴",trinidad_tobago:"🇹🇹",tunisia:"🇹🇳",tr:"🇹🇷",turkmenistan:"🇹🇲",turks_caicos_islands:"🇹🇨",tuvalu:"🇹🇻",uganda:"🇺🇬",ukraine:"🇺🇦",united_arab_emirates:"🇦🇪",gb:"🇬🇧",uk:"🇬🇧",us:"🇺🇸",us_virgin_islands:"🇻🇮",uruguay:"🇺🇾",uzbekistan:"🇺🇿",vanuatu:"🇻🇺",vatican_city:"🇻🇦",venezuela:"🇻🇪",vietnam:"🇻🇳",wallis_futuna:"🇼🇫",western_sahara:"🇪🇭",yemen:"🇾🇪",zambia:"🇿🇲",zimbabwe:"🇿🇼"}},Rzq8:function(e,t,r){"use strict";t.a={props:{search:String,select:Number,enter:Boolean},data:function(){return{showItems:[],items:[]}},mounted:function(){this.fetchFileNav()},watch:{search:function(e){var t=[];for(var r in this.items)this.items[r].name.indexOf(e)>=0&&t.push(this.items[r]);this.showItems=t,this.$emit("updateShowLen",this.showItems.length)},enter:function(e){e&&(this.$emit("close"),this.$bus.$emit("gotoLine",this.showItems[this.select].line))}},methods:{fetchFileNav:function(){var e=this;this.$http.get("/func-nav?file="+encodeURI(this.$bus.curSourceFile)).then(function(t){e.search="";var r=[];for(var a in t.data){var n=t.data[a];n.class?r.push({name:n.name,prototype:n.class+"::"+n.name+"("+n.params+")",line:n.line}):r.push({name:n.name,prototype:n.name+"("+n.params+")",line:n.line})}e.items=r,e.showItems=e.items,e.$emit("updateShowLen",e.showItems.length)})},rowClicked:function(e){this.$emit("close"),this.$bus.$emit("gotoLine",e)}}}},T5h1:function(e,t,r){"use strict";var a=r("mvHQ"),n=r.n(a);t.a={props:{search:String,select:Number,enter:Boolean},data:function(){return{showItems:[],items:[]}},mounted:function(){this.fetchBreakpoints()},watch:{search:function(e){var t=[];for(var r in this.items)this.items[r].file.indexOf(e)>=0&&t.push(this.items[r]);this.showItems=t,this.$emit("updateShowLen",this.showItems.length)},enter:function(e){if(e){this.$emit("close");var t=this.showItems[this.select];this.$bus.$emit("openFile",t.file,t.line)}}},methods:{fetchBreakpoints:function(){var e=[];for(var t in window.localStorage){var r=JSON.parse(window.localStorage[t]);for(var a in r)e.push({file:t,line:a})}this.items=e,this.showItems=this.items,this.$emit("updateShowLen",this.showItems.length)},rowClicked:function(e){this.$emit("close"),this.$bus.$emit("openFile",e.file,e.line)},remove:function(e){var t=this.$localStorage.get(e.file);t&&(t=JSON.parse(t),delete t[e.line],this.$localStorage.set(e.file,n()(t)),this.$bus.$emit("removeBp",e.file,e.line),this.fetchBreakpoints())}}}},Txe8:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("svg",{class:e.klass,style:e.style,attrs:{version:"1.1",role:e.label?"img":"presentation","aria-label":e.label,x:e.x,y:e.y,width:e.width,height:e.height,viewBox:e.box}},[e._t("default",[e.icon&&e.icon.paths?e._l(e.icon.paths,function(t,a){return r("path",e._b({key:"path-"+a},"path",t,!1))}):e._e(),e._v(" "),e.icon&&e.icon.polygons?e._l(e.icon.polygons,function(t,a){return r("polygon",e._b({key:"polygon-"+a},"polygon",t,!1))}):e._e(),e._v("\b\n "),e.icon&&e.icon.raw?[r("g",{domProps:{innerHTML:e._s(e.raw)}})]:e._e()])],2)},n=[],i={render:a,staticRenderFns:n};t.a=i},UtXa:function(e,t,r){"use strict";function a(e){r("5abi")}var n=r("Rzq8"),i=r("/E90"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-087f4174",null);t.a=l.exports},"Wq+S":function(e,t,r){"use strict";function a(e){r("seGP")}var n=r("K5QJ"),i=r("1Bj8"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-24870b3c",null);t.a=l.exports},XDsQ:function(e,t,r){"use strict";function a(e){r("hUBu")}var n=r("px5a"),i=r("10oB"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-01b04102",null);t.a=l.exports},YaEn:function(e,t,r){"use strict";var a=r("7+uW"),n=r("/ocq"),i=r("eWLx"),o=r("42Hy"),s=r("lO7g");a.a.use(n.a),t.a=new n.a({routes:[{path:"/trace/source/:id",name:"Source",component:i.a},{path:"/home",name:"Home",component:s.a},{path:"/",name:"Index",component:o.a}]})},aGEy:function(e,t){},bpnn:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("b-modal",{ref:"popupList",attrs:{"hide-header":"","hide-footer":"",size:"lg"},on:{shown:e.searchInputFocus}},[r("div",{staticStyle:{padding:"0 10rem","margin-bottom":"1rem"}},[r("b-form-input",{ref:"searchInput",attrs:{type:"text"},model:{value:e.search,callback:function(t){e.search=t},expression:"search"}})],1),e._v(" "),"traces-nav"===e.type?r("traces-nav",{attrs:{enter:e.enter,search:e.search,select:e.select},on:{close:e.close,updateShowLen:e.updateShowLen}}):e._e(),e._v(" "),"func-nav"===e.type?r("func-nav",{attrs:{enter:e.enter,search:e.search,select:e.select},on:{close:e.close,updateShowLen:e.updateShowLen}}):e._e(),e._v(" "),"file-nav"===e.type?r("file-nav",{attrs:{enter:e.enter,search:e.search,select:e.select},on:{close:e.close,updateShowLen:e.updateShowLen}}):e._e(),e._v(" "),"breakpoint-nav"===e.type?r("breakpoint-nav",{attrs:{enter:e.enter,search:e.search,select:e.select},on:{close:e.close,updateShowLen:e.updateShowLen}}):e._e()],1)},n=[],i={render:a,staticRenderFns:n};t.a=i},cCV5:function(e,t){},cUy1:function(e,t,r){"use strict";t.a={props:{search:String,select:Number,enter:Boolean},data:function(){return{showItems:[],items:[]}},mounted:function(){this.fetchFileNav()},watch:{search:function(e){var t=[];for(var r in this.items)this.items[r].indexOf(e)>=0&&t.push(this.items[r]);this.showItems=t,this.$emit("updateShowLen",this.showItems.length)},enter:function(e){e&&(this.$emit("close"),this.$bus.$emit("openFile",this.showItems[this.select]))}},methods:{fetchFileNav:function(){var e=this;this.$http.get("/file-nav/"+this.$route.params.id).then(function(t){e.search="",e.items=t.data,e.showItems=e.items,e.$emit("updateShowLen",e.showItems.length)})},rowClicked:function(e){this.$emit("close"),this.$bus.$emit("openFile",e)}}}},chry:function(e,t){},dXrS:function(e,t,r){"use strict";function a(){return"fa-"+(i++).toString(16)}var n={};t.a={name:"icon",props:{name:{type:String,validator:function(e){return e?e in n||(console.warn('Invalid prop: prop "name" is referring to an unregistered icon "'+e+'".\nPlesase make sure you have imported this icon before using it.'),!1):(console.warn('Invalid prop: prop "name" is required.'),!1)}},scale:[Number,String],spin:Boolean,inverse:Boolean,pulse:Boolean,flip:{validator:function(e){return"horizontal"===e||"vertical"===e}},label:String},data:function(){return{x:!1,y:!1,childrenWidth:0,childrenHeight:0,outerScale:1}},computed:{normalizedScale:function(){var e=this.scale;return e=void 0===e?1:Number(e),isNaN(e)||e<=0?(console.warn('Invalid prop: prop "scale" should be a number over 0.',this),this.outerScale):e*this.outerScale},klass:function(){return{"fa-icon":!0,"fa-spin":this.spin,"fa-flip-horizontal":"horizontal"===this.flip,"fa-flip-vertical":"vertical"===this.flip,"fa-inverse":this.inverse,"fa-pulse":this.pulse}},icon:function(){return this.name?n[this.name]:null},box:function(){return this.icon?"0 0 "+this.icon.width+" "+this.icon.height:"0 0 "+this.width+" "+this.height},ratio:function(){if(!this.icon)return 1;var e=this.icon,t=e.width,r=e.height;return Math.max(t,r)/16},width:function(){return this.childrenWidth||this.icon&&this.icon.width/this.ratio*this.normalizedScale||0},height:function(){return this.childrenHeight||this.icon&&this.icon.height/this.ratio*this.normalizedScale||0},style:function(){return 1!==this.normalizedScale&&{fontSize:this.normalizedScale+"em"}},raw:function(){if(!this.icon||!this.icon.raw)return null;var e=this.icon.raw,t={};return e=e.replace(/\s(?:xml:)?id=["']?([^"')\s]+)/g,function(e,r){var n=a();return t[r]=n,' id="'+n+'"'}),e=e.replace(/#(?:([^'")\s]+)|xpointer\(id\((['"]?)([^')]+)\2\)\))/g,function(e,r,a,n){var i=r||n;return i&&t[i]?"#"+t[i]:e}),e}},mounted:function(){var e=this;if(!this.icon){this.$children.forEach(function(t){t.outerScale=e.normalizedScale});var t=0,r=0;this.$children.forEach(function(e){t=Math.max(t,e.width),r=Math.max(r,e.height)}),this.childrenWidth=t,this.childrenHeight=r,this.$children.forEach(function(e){e.x=(t-e.width)/2,e.y=(r-e.height)/2})}},register:function(e){for(var t in e){var r=e[t];r.paths||(r.paths=[]),r.d&&r.paths.push({d:r.d}),r.polygons||(r.polygons=[]),r.points&&r.polygons.push({points:r.points}),n[t]=r}},icons:n};var i=870711},dcIi:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("b-container",{staticStyle:{"text-align":"center"}},[r("b-row",[r("b-col",{staticStyle:{"text-align":"left"}},[r("div",{staticStyle:{margin:"1rem 0"}},[r("b-button",{attrs:{variant:"danger"},on:{click:function(t){e.clearTraces()}}},[e._v("Clear Traces")]),e._v(" "),r("b-button",{attrs:{variant:"outline-primary"},on:{click:function(t){e.fetchTraces()}}},[e._v("Refresh")])],1),e._v(" "),r("b-table",{attrs:{hover:"",items:e.files,fields:e.fields},on:{"row-clicked":e.rowClicked}})],1)],1)],1)},n=[],i={render:a,staticRenderFns:n};t.a=i},eWLx:function(e,t,r){"use strict";function a(e){r("aGEy"),r("y7ny")}var n=r("68IZ"),i=r("rApO"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-6dec0ee4",null);t.a=l.exports},ejnp:function(e,t,r){"use strict";t.a={data:function(){return{GUI:"__Home 页面__: 列出所有的跟踪文件, 通过点击列表中的某行记录打开Source 页面。\n+ Clear Traces: 删除所有的跟踪文件。\n+ Refresh: 刷新列表。\n+ 列表字段说明:\n - Sapi: cli, fpm-fcgi 等\n - Method: fpm-fcgi中的http 请求方法\n - Uri: fpm-fcgi中的http 请求路径及参数\n - File: 跟踪文件名\n - Size: 跟踪文件大小\n - Time: 跟踪文件创建时间\n\n__Source Page__: 显示跟踪内容详情。\n+ 左边模块显示源码文件,右边模块显示跟踪到的变量值。\n - 只跟踪赋值和函数调用\n - ++、--、+=、/=、-=、*=、%=等,显示的值是这些运算符执行之前的值\n - PHP 7无法获取到扩展函数的参数名称(无法显示参数名称的会显示为$...)\n+ 被执行过的代码行,行号会以绿色高亮出来,深绿色表示当前执行所在的行\n - 点击高亮的行号,可以将执行跳转至对应行\n - ctrl+点击行号,可以设置或取消断点(断点的行号会以红色高亮)\n+ 执行操作:\n - step into: 同gdb\n - step back: 根据你的执行历史,往回执行\n - step over: 同gdb\n - step out: 同gdb\n - continue: 同gdb,执行到下一个断点\n - reset:重置执行过程\n+ 快捷键:\n - ctrl+o: 打开最新10个跟踪文件的列表浮框\n - ctrl+p: 打开被跟踪到的源码文件的列表浮框,只能在Source 页面使用\n - ctrl+r: 打开当前显示的源码文件函数/方法的列表浮框,只能在Source 页面使用\n - ctrl+b: 打开断点列表浮框,只能在Source 页面使用\n\n[ytrace_gui](https://github.com/yangxikun/ytrace_gui)\n[report issue](https://github.com/yangxikun/ytrace_gui/issues)\n ",ChromeExtension:"__Options__\n+ ytrace.*_name: 配置cookie的名称,必须与ytrace.ini保持一致,通常不需要更改默认值。\n\n__弹框__\n+ 开启/关闭跟踪\n+ 设置跟踪的配置,ytrace PHP扩展会从cookie里检测它们。\n\n[ytrace_chrome_extension](https://github.com/yangxikun/ytrace_chrome_extension)\n[report issue](https://github.com/yangxikun/ytrace_chrome_extension/issues)\n ",PHPExtension:'__INI 配置__\n+ auto_enable: 类型:boolean,默认值:0, PHP_INI_SYSTEM.\n+ enable_trigger: 类型:boolean,默认值:0, PHP_INI_SYSTEM.\n - 当设置为1时,你可以通过名为YTRACE_TRIGGER的GET/POST参数,或cookie,或环境变量来触发跟踪\n+ enable_trigger_name: 类型:string,默认值:YTRACE_TRIGGER, PHP_INI_SYSTEM.\n+ enable_trigger_value: 类型:string,默认值:"", PHP_INI_SYSTEM.\n - 用于限制触发跟踪的值\n - 当为空字符串时,只要检测到有YTRACE_TRIGGER名称的GET/POST参数,或cookie,或环境变量时,就会触发跟踪\n - 当为非空字符串时,名称为YTRACE_TRIGGER的GET/POST参数,或cookie,或环境变量对应的值必须与之匹配\n+ output_dir: 类型:string,默认值: /tmp, PHP_INI_SYSTEM.\n - 确保有写权限\n+ output_format: 类型:string,默认值: trace-%t, PHP_INI_SYSTEM.\n - 跟踪文件命名\n - %t: 秒级时间戳\n - %u: 毫秒级时间戳\n - %p: pid\n - %H: $_SERVER[\'HTTP_HOST\']\n - %U: $_SERVER[\'UNIQUE_ID\']\n - %R: $_SERVER[\'REQUEST_URI\']\n - %%: %字面量\n+ white_list: 类型:string,默认值: "", PHP_INI_ALL.\n - 由逗号分隔的多个字符串组成,大小写敏感\n - 当设置它的值时,例如“controller,model”,那么只有源码文件路径包含“controller”或“model”,才会被跟踪\n - white_list优先级高于black_list\n+ white_list_name: 类型:string,默认值: "YTRACE_WHITE_LIST", PHP_INI_SYSTEM.\n+ black_list: 类型:string,默认值: "", PHP_INI_ALL.\n - 由逗号分隔的多个字符串组成,大小写敏感\n - 当设置它的值时,例如“vendor,lib”,如果源码文件路径包含“vendor”或“lib”,将不会被跟踪\n+ black_list_name: 类型:string,默认值: "YTRACE_BLACK_LIST", PHP_INI_SYSTEM.\n+ var_display_max_children: 类型:integer,默认值: 128, PHP_INI_ALL.\n - Controls the amount of array children and object\'s properties are traced.\n - 控制跟踪到的变量值最大的数组元素个数和对象的属性个数\n - 最大值是 32\n+ var_display_max_children_name 类型:string,默认值: "YTRACE_VAR_DISPLAY_MAX_CHILDREN", PHP_INI_SYSTEM.\n+ var_display_max_data: 类型:integer,默认值: 512, PHP_INI_ALL.\n - Controls the maximum string length that is traced.\n - 控制跟踪到的字符串变量值的最大长度\n - 最大值 1024\n+ var_display_max_data_name 类型:string,默认值: "YTRACE_VAR_DISPLAY_MAX_DATA", PHP_INI_SYSTEM.\n+ var_display_max_depth: 类型:integer,默认值: 3, PHP_INI_ALL.\n - 控制跟踪到的变量值的最大嵌套层级\n - 最大 16\n+ var_display_max_depth_name 类型:string,默认值: "YTRACE_VAR_DISPLAY_MAX_DEPTH", PHP_INI_SYSTEM.\n==通常,你不需要修改*_name配置的默认值。*_name的配置是用于设置cookie、环境变量、GET/POST参数的名称。==\n\n__PHP 函数__\n+ ytrace_enable ([$traced_file_name])\n - 开启跟踪,并写入到$traced_file_name\n+ ytrace_disable ()\n - 停止跟踪,返回跟踪文件名\n\n[ytrace](https://github.com/yangxikun/ytrace)\n[report issue](https://github.com/yangxikun/ytrace/issues)\n '}}}},fWJJ:function(e,t,r){"use strict";function a(e){r("DUku")}var n=r("cUy1"),i=r("RQcw"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-2f888d8e",null);t.a=l.exports},h02k:function(e,t,r){"use strict";var a=r("Jltp"),n=r("bpnn"),i=r("VU/8"),o=i(a.a,n.a,null,null,null);t.a=o.exports},hUBu:function(e,t){},hpS7:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{attrs:{id:"app"}},[r("div",{attrs:{id:"head"}},[r("b-navbar",{attrs:{toggleable:"md",type:"light",variant:"light"}},[r("b-nav-toggle",{attrs:{target:"nav_collapse"}}),e._v(" "),r("b-navbar-brand",{attrs:{href:"#"}},[r("router-link",{staticClass:"nav-link",attrs:{to:"/"}},[e._v("Ytrace")])],1),e._v(" "),r("b-collapse",{attrs:{"is-nav":"",id:"nav_collapse"}},[r("b-nav",{attrs:{"is-nav-bar":""}},[r("b-nav-item",[r("router-link",{staticClass:"nav-link",class:{active:"Home"==e.nav},attrs:{to:"/home"}},[e._v("Home")])],1),e._v(" "),r("b-nav-item",[r("router-link",{staticClass:"nav-link",class:{disabled:""==e.traceId,active:"Source"==e.nav},attrs:{event:e.traceId?"click":"",to:"/trace/source/"+e.traceId}},[e._v("Source")])],1)],1)],1)],1)],1),e._v(" "),r("keep-alive",{attrs:{exclude:"Home"}},[r("router-view")],1),e._v(" "),r("popup-list")],1)},n=[],i={render:a,staticRenderFns:n};t.a=i},lO7g:function(e,t,r){"use strict";function a(e){r("OUSy"),r("HCoV")}var n=r("Fs8J"),i=r("dcIi"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-7eb551e8",null);t.a=l.exports},lzLh:function(e,t,r){"use strict";function a(e){r("Icg2")}var n=r("T5h1"),i=r("wYtO"),o=r("VU/8"),s=a,l=o(n.a,i.a,s,"data-v-59939b8e",null);t.a=l.exports},px5a:function(e,t,r){"use strict";t.a={data:function(){return{GUI:"__Home Page__: List all traced files, click on one of the items in the list to open source page.\n+ Clear Traces: delete all traced files.\n+ Refresh: update list.\n+ List field explanation:\n - Sapi: cli, fpm-fcgi etc\n - Method: http method in fpm-fcgi\n - Uri: http request uri in fpm-fcgi\n - File: file name\n - Size: file size\n - Time: created time\n\n__Source Page__: show detail of traced files.\n+ source code show in left side, traced value show in right side.\n - only assignment and function call will be traced\n - ++, --, +=, /=, -=, *=, %= etc, shows the values before these operators execute\n - PHP 7 cannot show internal function parameters name (parameter name cannot be found will be showed as $...)\n+ executed line will be highlight in green, dark green means current execute\n - click highlighted line number, can jump current execute to it\n - ctrl+click line number, can set/clear a breakpoint (breakpoint will be highlight in red line number)\n+ execute operation:\n - step into: same with gdb\n - step back: execute back through your step history\n - step over: same with gdb\n - step out: same with gdb\n - continue: same with gdb, execute to next breakpoint\n - reset: reset execute to first entry\n+ shortcut:\n - ctrl+o: open 10 latest traced file popup list\n - ctrl+p: open traced source file popup list, only available in source page\n - ctrl+r: open current source file function/method popup list, only available in source page\n - ctrl+b: open breakpoints popup list, only available in source page\n\n[ytrace_gui](https://github.com/yangxikun/ytrace_gui)\n[report issue](https://github.com/yangxikun/ytrace_gui/issues)\n ",ChromeExtension:"__Options__\n+ ytrace.*_name: cookie name will be used, must be same with ytrace.ini config, generally you don't need to change the default config.\n\n__Popup__\n+ enable/disable trace\n+ set trace config, ytrace php extension will detect it from cookie\n\n[ytrace_chrome_extension](https://github.com/yangxikun/ytrace_chrome_extension)\n[report issue](https://github.com/yangxikun/ytrace_chrome_extension/issues)\n ",PHPExtension:'__INI config__\n+ auto_enable: Type: boolean, Default value: 0, PHP_INI_SYSTEM.\n+ enable_trigger: Type: boolean, Default value: 0, PHP_INI_SYSTEM.\n - When this setting is set to 1, you can trigger the generation of trace files by using the YTRACE_TRIGGER GET/POST parameter, or set a cookie with the name YTRACE_TRIGGER, or set an environment variable with the name YTRACE_TRIGGER.\n+ enable_trigger_name: Type: string, Default value: YTRACE_TRIGGER, PHP_INI_SYSTEM.\n+ enable_trigger_value: Type: string, Defalut value: "", PHP_INI_SYSTEM.\n - This setting can be used to restrict who can make use of the YTRACE_TRIGGER functionality as outlined in ytrace.enable_trigger.\n - When changed from its default value of an empty string, the value of the cookie, environment variable, GET or POST argument needs to match the shared secret set with this setting in order for the trace file to be generated.\n+ output_dir: Type: string, Default value: /tmp, PHP_INI_SYSTEM.\n - make sure has write permission.\n+ output_format: Type: string, Default value: trace-%t, PHP_INI_SYSTEM.\n - name format of traced file\n - %t: timestamp (in seconds)\n - %u: timestamp (in microseconds)\n - %p: pid\n - %H: $_SERVER[\'HTTP_HOST\']\n - %U: $_SERVER[\'UNIQUE_ID\']\n - %R: $_SERVER[\'REQUEST_URI\']\n - %%: literal %\n+ white_list: Type: string, Default value: "", PHP_INI_ALL.\n - comma separated string, case sensitive.\n - When set its value, sunch as "controller,model", only executed source file path that contain "controller" or "model" will be traced.\n - white_list takes precedence over black_list.\n+ white_list_name: Type: string, Default value: "YTRACE_WHITE_LIST", PHP_INI_SYSTEM.\n+ black_list: Type: string, Default value: "", PHP_INI_ALL.\n - comma separated string, case sensitive.\n - When set its value, sunch as "vendor,lib", executed source file path that contain "vendor" or "lib" will not be traced.\n+ black_list_name: Type: string, Default value: "YTRACE_BLACK_LIST", PHP_INI_SYSTEM.\n+ var_display_max_children: Type: integer, Default value: 128, PHP_INI_ALL.\n - Controls the amount of array children and object\'s properties are traced.\n - max value 32\n+ var_display_max_children_name Type: string, Default value: "YTRACE_VAR_DISPLAY_MAX_CHILDREN", PHP_INI_SYSTEM.\n+ var_display_max_data: Type: integer, Default value: 512, PHP_INI_ALL.\n - Controls the maximum string length that is traced.\n - max value 1024\n+ var_display_max_data_name Type: string, Default value: "YTRACE_VAR_DISPLAY_MAX_DATA", PHP_INI_SYSTEM.\n+ var_display_max_depth: Type: integer, Default value: 3, PHP_INI_ALL.\n - Controls how many nested levels of array elements and object properties are traced.\n - max value 16\n+ var_display_max_depth_name Type: string, Default value: "YTRACE_VAR_DISPLAY_MAX_DEPTH", PHP_INI_SYSTEM.\n==Generally, you don’t need to change the default config of *_name. The value of *_name is used for the name of cookie, environment variable, GET or POST argument==\n\n__PHP function__\n+ ytrace_enable ([$traced_file_name])\n - enable trace when trace is disable, write trace to $traced_file_name.\n+ ytrace_disable ()\n - disable trace when trace is enable, return traced file.\n\n[ytrace](https://github.com/yangxikun/ytrace)\n[report issue](https://github.com/yangxikun/ytrace/issues)\n '}}}},"qE0+":function(e,t){},rApO:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",[r("div",{directives:[{name:"show",rawName:"v-show",value:!e.loading,expression:"!loading"}]},[r("div",{staticStyle:{padding:"0.5rem 1rem"}},[r("h6",{directives:[{name:"show",rawName:"v-show",value:e.file,expression:"file"}],staticStyle:{display:"inline-block",color:"rgba(0, 0, 0, 0.5)"}},[e._v(e._s(e.file)+":"+e._s(e.line))]),e._v(" "),r("b-button",{attrs:{size:"sm",variant:"outline-secondary"},on:{click:function(t){e.reset(0)}}},[e._v("reset")]),e._v(" "),r("b-button",{attrs:{disabled:e.step==e.items.length-1,size:"sm",variant:"outline-secondary"},on:{click:function(t){e._continue()}}},[e._v("continue")]),e._v(" "),r("b-button",{attrs:{disabled:e.step==e.items.length-1,size:"sm",variant:"outline-secondary"},on:{click:function(t){e.stepOut()}}},[e._v("step out")]),e._v(" "),r("b-button",{attrs:{disabled:e.step==e.items.length-1,size:"sm",variant:"outline-secondary"},on:{click:function(t){e.stepOver()}}},[e._v("step over")]),e._v(" "),r("b-button",{attrs:{size:"sm",variant:"outline-secondary"},on:{click:function(t){e.stepBack()}}},[e._v("step back")]),e._v(" "),r("b-button",{attrs:{disabled:e.step==e.items.length-1,size:"sm",variant:"outline-secondary"},on:{click:function(t){e.stepInto(e.step,e.step+1)}}},[e._v("step into")])],1),e._v(" "),r("div",{staticClass:"container-fluid"},[r("b-row",[r("b-col",{attrs:{cols:"8"}},[r("div",{ref:"code",staticStyle:{width:"100%","font-size":"1rem"},style:{height:e.codeHeight+"px"}})]),e._v(" "),r("b-col",[r("div",{ref:"var",staticStyle:{width:"100%","font-size":"1rem"},style:{height:e.codeHeight+"px"}})])],1)],1)]),e._v(" "),r("div",{directives:[{name:"show",rawName:"v-show",value:e.loading,expression:"loading"}],staticStyle:{"margin-top":"5%"}},[r("vue-loading",{attrs:{type:"bars",color:"#d9544e",size:{width:"8rem",height:"6rem"}}})],1)])},n=[],i={render:a,staticRenderFns:n};t.a=i},seGP:function(e,t){},wYtO:function(e,t,r){"use strict";var a=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("b-list-group",{staticStyle:{"max-height":"35rem"}},e._l(e.showItems,function(t,a){return r("b-list-group-item",{key:a,class:{active:a===e.select},on:{click:function(r){e.rowClicked(t)}}},[e._v("\n "+e._s(t.file)+": "+e._s(t.line)+"\n "),r("div",{staticStyle:{display:"inline-block",float:"right"},on:{click:function(r){r.stopPropagation(),e.remove(t)}}},[r("icon",{attrs:{name:"close"}})],1)])}))},n=[],i={render:a,staticRenderFns:n};t.a=i},xJD8:function(e,t,r){"use strict";var a=r("h02k");t.a={name:"app",components:{PopupList:a.a},data:function(){return{nav:"Home",traceId:""}},watch:{$route:"activateNav"},mounted:function(){var e=this;this.$bus.$on("clearTraces",function(){e.traceId=""}),this.activateNav()},methods:{activateNav:function(){this.nav=this.$route.name,this.$route.params.id&&(this.traceId=this.$route.params.id)}}}},y7ny:function(e,t){}},["NHnr"]); -------------------------------------------------------------------------------- /static/js/manifest.3dff49ac782c8e4820fb.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var i,u,f,s=0,l=[];s 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /webui/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /webui/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /webui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 26 | 'no-new-func': 0 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /webui/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /webui/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /webui/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /webui/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict' 3 | require('eventsource-polyfill') 4 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 5 | 6 | hotClient.subscribe(function (event) { 7 | if (event.action === 'reload') { 8 | window.location.reload() 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /webui/build/dev-server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | const config = require('../config') 5 | if (!process.env.NODE_ENV) { 6 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 7 | } 8 | 9 | const opn = require('opn') 10 | const path = require('path') 11 | const express = require('express') 12 | const webpack = require('webpack') 13 | const proxyMiddleware = require('http-proxy-middleware') 14 | const webpackConfig = require('./webpack.dev.conf') 15 | 16 | // default port where dev server listens for incoming traffic 17 | const port = process.env.PORT || config.dev.port 18 | // automatically open browser, if not set will be false 19 | const autoOpenBrowser = !!config.dev.autoOpenBrowser 20 | // Define HTTP proxies to your custom API backend 21 | // https://github.com/chimurai/http-proxy-middleware 22 | const proxyTable = config.dev.proxyTable 23 | 24 | const app = express() 25 | const compiler = webpack(webpackConfig) 26 | 27 | const devMiddleware = require('webpack-dev-middleware')(compiler, { 28 | publicPath: webpackConfig.output.publicPath, 29 | quiet: true 30 | }) 31 | 32 | const hotMiddleware = require('webpack-hot-middleware')(compiler, { 33 | log: false, 34 | heartbeat: 2000 35 | }) 36 | // force page reload when html-webpack-plugin template changes 37 | // currently disabled until this is resolved: 38 | // https://github.com/jantimon/html-webpack-plugin/issues/680 39 | // compiler.plugin('compilation', function (compilation) { 40 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 41 | // hotMiddleware.publish({ action: 'reload' }) 42 | // cb() 43 | // }) 44 | // }) 45 | 46 | // enable hot-reload and state-preserving 47 | // compilation error display 48 | app.use(hotMiddleware) 49 | 50 | // proxy api requests 51 | Object.keys(proxyTable).forEach(function (context) { 52 | const options = proxyTable[context] 53 | if (typeof options === 'string') { 54 | options = { target: options } 55 | } 56 | app.use(proxyMiddleware(options.filter || context, options)) 57 | }) 58 | 59 | // handle fallback for HTML5 history API 60 | app.use(require('connect-history-api-fallback')()) 61 | 62 | // serve webpack bundle output 63 | app.use(devMiddleware) 64 | 65 | // serve pure static assets 66 | const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 67 | app.use(staticPath, express.static('./static')) 68 | 69 | const uri = 'http://localhost:' + port 70 | 71 | var _resolve 72 | var _reject 73 | var readyPromise = new Promise((resolve, reject) => { 74 | _resolve = resolve 75 | _reject = reject 76 | }) 77 | 78 | var server 79 | var portfinder = require('portfinder') 80 | portfinder.basePort = port 81 | 82 | console.log('> Starting dev server...') 83 | devMiddleware.waitUntilValid(() => { 84 | portfinder.getPort((err, port) => { 85 | if (err) { 86 | _reject(err) 87 | } 88 | process.env.PORT = port 89 | var uri = 'http://localhost:' + port 90 | console.log('> Listening at ' + uri + '\n') 91 | // when env is testing, don't need open it 92 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 93 | opn(uri) 94 | } 95 | server = app.listen(port) 96 | _resolve() 97 | }) 98 | }) 99 | 100 | module.exports = { 101 | ready: readyPromise, 102 | close: () => { 103 | server.close() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /webui/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | 6 | exports.assetsPath = function (_path) { 7 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 8 | ? config.build.assetsSubDirectory 9 | : config.dev.assetsSubDirectory 10 | return path.posix.join(assetsSubDirectory, _path) 11 | } 12 | 13 | exports.cssLoaders = function (options) { 14 | options = options || {} 15 | 16 | const cssLoader = { 17 | loader: 'css-loader', 18 | options: { 19 | minimize: process.env.NODE_ENV === 'production', 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | // generate loader string to be used with extract text plugin 25 | function generateLoaders (loader, loaderOptions) { 26 | const loaders = [cssLoader] 27 | if (loader) { 28 | loaders.push({ 29 | loader: loader + '-loader', 30 | options: Object.assign({}, loaderOptions, { 31 | sourceMap: options.sourceMap 32 | }) 33 | }) 34 | } 35 | 36 | // Extract CSS when that option is specified 37 | // (which is the case during production build) 38 | if (options.extract) { 39 | return ExtractTextPlugin.extract({ 40 | use: loaders, 41 | fallback: 'vue-style-loader' 42 | }) 43 | } else { 44 | return ['vue-style-loader'].concat(loaders) 45 | } 46 | } 47 | 48 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 49 | return { 50 | css: generateLoaders(), 51 | postcss: generateLoaders(), 52 | less: generateLoaders('less'), 53 | sass: generateLoaders('sass', { indentedSyntax: true }), 54 | scss: generateLoaders('sass'), 55 | stylus: generateLoaders('stylus'), 56 | styl: generateLoaders('stylus') 57 | } 58 | } 59 | 60 | // Generate loaders for standalone style files (outside of .vue) 61 | exports.styleLoaders = function (options) { 62 | const output = [] 63 | const loaders = exports.cssLoaders(options) 64 | for (const extension in loaders) { 65 | const loader = loaders[extension] 66 | output.push({ 67 | test: new RegExp('\\.' + extension + '$'), 68 | use: loader 69 | }) 70 | } 71 | return output 72 | } 73 | -------------------------------------------------------------------------------- /webui/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | 6 | module.exports = { 7 | loaders: utils.cssLoaders({ 8 | sourceMap: isProduction 9 | ? config.build.productionSourceMap 10 | : config.dev.cssSourceMap, 11 | extract: isProduction 12 | }), 13 | transformToRequire: { 14 | video: 'src', 15 | source: 'src', 16 | img: 'src', 17 | image: 'xlink:href' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /webui/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | entry: { 13 | app: './src/main.js' 14 | }, 15 | output: { 16 | path: config.build.assetsRoot, 17 | filename: '[name].js', 18 | publicPath: process.env.NODE_ENV === 'production' 19 | ? config.build.assetsPublicPath 20 | : config.dev.assetsPublicPath 21 | }, 22 | resolve: { 23 | extensions: ['.js', '.vue', '.json'], 24 | alias: { 25 | 'vue$': 'vue/dist/vue.esm.js', 26 | '@': resolve('src'), 27 | } 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.(js|vue)$/, 33 | loader: 'eslint-loader', 34 | enforce: 'pre', 35 | include: [resolve('src'), resolve('test')], 36 | options: { 37 | formatter: require('eslint-friendly-formatter') 38 | } 39 | }, 40 | { 41 | test: /\.vue$/, 42 | loader: 'vue-loader', 43 | options: vueLoaderConfig 44 | }, 45 | { 46 | test: /\.js$/, 47 | loader: 'babel-loader', 48 | include: [resolve('src'), resolve('test')] 49 | }, 50 | { 51 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 52 | loader: 'url-loader', 53 | options: { 54 | limit: 10000, 55 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 56 | } 57 | }, 58 | { 59 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 60 | loader: 'url-loader', 61 | options: { 62 | limit: 10000, 63 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 64 | } 65 | }, 66 | { 67 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 68 | loader: 'url-loader', 69 | options: { 70 | limit: 10000, 71 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 72 | } 73 | } 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /webui/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | 10 | // add hot-reload related code to entry chunks 11 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 12 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 13 | }) 14 | 15 | module.exports = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 18 | }, 19 | // cheap-module-eval-source-map is faster for development 20 | devtool: '#cheap-module-eval-source-map', 21 | plugins: [ 22 | new webpack.DefinePlugin({ 23 | 'process.env': config.dev.env 24 | }), 25 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 26 | new webpack.HotModuleReplacementPlugin(), 27 | new webpack.NoEmitOnErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true 33 | }), 34 | new FriendlyErrorsPlugin() 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /webui/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | 13 | const env = config.build.env 14 | 15 | const webpackConfig = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ 18 | sourceMap: config.build.productionSourceMap, 19 | extract: true 20 | }) 21 | }, 22 | devtool: config.build.productionSourceMap ? '#source-map' : false, 23 | output: { 24 | path: config.build.assetsRoot, 25 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 26 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 27 | }, 28 | plugins: [ 29 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 30 | new webpack.DefinePlugin({ 31 | 'process.env': env 32 | }), 33 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | }, 38 | sourceMap: true 39 | }), 40 | // extract css into its own file 41 | new ExtractTextPlugin({ 42 | filename: utils.assetsPath('css/[name].[contenthash].css') 43 | }), 44 | // Compress extracted CSS. We are using this plugin so that possible 45 | // duplicated CSS from different components can be deduped. 46 | new OptimizeCSSPlugin({ 47 | cssProcessorOptions: { 48 | safe: true 49 | } 50 | }), 51 | // generate dist index.html with correct asset hash for caching. 52 | // you can customize output by editing /index.html 53 | // see https://github.com/ampedandwired/html-webpack-plugin 54 | new HtmlWebpackPlugin({ 55 | filename: config.build.index, 56 | template: 'index.html', 57 | inject: true, 58 | minify: { 59 | removeComments: true, 60 | collapseWhitespace: true, 61 | removeAttributeQuotes: true 62 | // more options: 63 | // https://github.com/kangax/html-minifier#options-quick-reference 64 | }, 65 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 66 | chunksSortMode: 'dependency' 67 | }), 68 | // keep module.id stable when vender modules does not change 69 | new webpack.HashedModuleIdsPlugin(), 70 | // split vendor js into its own file 71 | new webpack.optimize.CommonsChunkPlugin({ 72 | name: 'vendor', 73 | minChunks: function (module) { 74 | // any required modules inside node_modules are extracted to vendor 75 | return ( 76 | module.resource && 77 | /\.js$/.test(module.resource) && 78 | module.resource.indexOf( 79 | path.join(__dirname, '../node_modules') 80 | ) === 0 81 | ) 82 | } 83 | }), 84 | // extract webpack runtime and module manifest to its own file in order to 85 | // prevent vendor hash from being updated whenever app bundle is updated 86 | new webpack.optimize.CommonsChunkPlugin({ 87 | name: 'manifest', 88 | chunks: ['vendor'] 89 | }), 90 | // copy custom static assets 91 | new CopyWebpackPlugin([ 92 | { 93 | from: path.resolve(__dirname, '../static'), 94 | to: config.build.assetsSubDirectory, 95 | ignore: ['.*'] 96 | } 97 | ]) 98 | ] 99 | }) 100 | 101 | if (config.build.productionGzip) { 102 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 103 | 104 | webpackConfig.plugins.push( 105 | new CompressionWebpackPlugin({ 106 | asset: '[path].gz[query]', 107 | algorithm: 'gzip', 108 | test: new RegExp( 109 | '\\.(' + 110 | config.build.productionGzipExtensions.join('|') + 111 | ')$' 112 | ), 113 | threshold: 10240, 114 | minRatio: 0.8 115 | }) 116 | ) 117 | } 118 | 119 | if (config.build.bundleAnalyzerReport) { 120 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 121 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 122 | } 123 | 124 | module.exports = webpackConfig 125 | -------------------------------------------------------------------------------- /webui/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /webui/config/index.js: -------------------------------------------------------------------------------- 1 | 'use stxrict' 2 | // Template version: 1.1.0 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | build: { 9 | env: require('./prod.env'), 10 | index: path.resolve(__dirname, '../../index.html'), 11 | assetsRoot: path.resolve(__dirname, '../..'), 12 | assetsSubDirectory: 'static', 13 | assetsPublicPath: '/', 14 | productionSourceMap: false, 15 | // Gzip off by default as many popular static hosts such as 16 | // Surge or Netlify already gzip all static assets for you. 17 | // Before setting to `true`, make sure to: 18 | // npm install --save-dev compression-webpack-plugin 19 | productionGzip: false, 20 | productionGzipExtensions: ['js', 'css'], 21 | // Run the build command with an extra argument to 22 | // View the bundle analyzer report after build finishes: 23 | // `npm run build --report` 24 | // Set to `true` or `false` to always turn it on or off 25 | bundleAnalyzerReport: process.env.npm_config_report 26 | }, 27 | dev: { 28 | env: require('./dev.env'), 29 | port: process.env.PORT || 8080, 30 | autoOpenBrowser: true, 31 | assetsSubDirectory: 'static', 32 | assetsPublicPath: '/', 33 | proxyTable: { 34 | '/trace': { 35 | target: 'http://localhost:8088', 36 | changeOrigin: true 37 | }, 38 | '/source': { 39 | target: 'http://localhost:8088', 40 | changeOrigin: true 41 | }, 42 | '/file-nav': { 43 | target: 'http://localhost:8088', 44 | changeOrigin: true 45 | }, 46 | '/func-nav': { 47 | target: 'http://localhost:8088', 48 | changeOrigin: true 49 | } 50 | }, 51 | // CSS Sourcemaps off by default because relative paths are "buggy" 52 | // with this option, according to the CSS-Loader README 53 | // (https://github.com/webpack/css-loader#sourcemaps) 54 | // In our experience, they generally work as expected, 55 | // just be aware of this issue when enabling this option. 56 | cssSourceMap: false 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /webui/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /webui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ytrace_gui 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /webui/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ytrace_gui", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async": { 8 | "version": "2.4.1", 9 | "resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz", 10 | "integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=", 11 | "dev": true, 12 | "requires": { 13 | "lodash": "4.17.4" 14 | } 15 | }, 16 | "compression-webpack-plugin": { 17 | "version": "1.0.1", 18 | "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-1.0.1.tgz", 19 | "integrity": "sha512-ABF2AFb31gpIBeEy/w6Ct0u+K+jY8jFRfGwjUWGxVTidA9pf7iH/JzjcVBQ+KB1gNMycujMxA56/PznMPUV5jw==", 20 | "dev": true, 21 | "requires": { 22 | "async": "2.4.1", 23 | "webpack-sources": "1.0.2" 24 | } 25 | }, 26 | "lodash": { 27 | "version": "4.17.4", 28 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 29 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", 30 | "dev": true 31 | }, 32 | "source-list-map": { 33 | "version": "2.0.0", 34 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", 35 | "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", 36 | "dev": true 37 | }, 38 | "source-map": { 39 | "version": "0.6.1", 40 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 41 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 42 | "dev": true 43 | }, 44 | "webpack-sources": { 45 | "version": "1.0.2", 46 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.2.tgz", 47 | "integrity": "sha512-Y7UddMCv6dGjy81nBv6nuQeFFIt5aalHm7uyDsAsW86nZwfOVPGRr3XMjEQLaT+WKo8rlzhC9qtbJvYKLtAwaw==", 48 | "dev": true, 49 | "requires": { 50 | "source-list-map": "2.0.0", 51 | "source-map": "0.6.1" 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /webui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ytrace_gui", 3 | "version": "1.0.0", 4 | "description": "ytrace gui", 5 | "author": "yangrokety@gmail.com", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "npm run dev", 10 | "build": "node build/build.js", 11 | "lint": "eslint --ext .js,.vue src" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.16.2", 15 | "bootstrap-vue": "^1.0.0-beta.9", 16 | "brace": "^0.10.0", 17 | "sprintf-js": "^1.1.1", 18 | "stylus": "^0.54.5", 19 | "stylus-loader": "^3.0.1", 20 | "vue": "^2.4.2", 21 | "vue-awesome": "^2.3.4", 22 | "vue-loading-template": "^0.1.7", 23 | "vue-localstorage": "^0.5.0", 24 | "vue-markdown": "^2.2.4", 25 | "vue-router": "^2.7.0" 26 | }, 27 | "devDependencies": { 28 | "autoprefixer": "^7.1.2", 29 | "babel-core": "^6.22.1", 30 | "babel-eslint": "^7.1.1", 31 | "babel-loader": "^7.1.1", 32 | "babel-plugin-transform-runtime": "^6.22.0", 33 | "babel-preset-env": "^1.3.2", 34 | "babel-preset-stage-2": "^6.22.0", 35 | "babel-register": "^6.22.0", 36 | "connect-history-api-fallback": "^1.3.0", 37 | "copy-webpack-plugin": "^4.0.1", 38 | "css-loader": "^0.28.0", 39 | "eslint": "^3.19.0", 40 | "eslint-config-standard": "^10.2.1", 41 | "eslint-friendly-formatter": "^3.0.0", 42 | "eslint-loader": "^1.7.1", 43 | "eslint-plugin-html": "^3.0.0", 44 | "eslint-plugin-import": "^2.7.0", 45 | "eslint-plugin-node": "^5.2.0", 46 | "eslint-plugin-promise": "^3.4.0", 47 | "eslint-plugin-standard": "^3.0.1", 48 | "eventsource-polyfill": "^0.9.6", 49 | "express": "^4.14.1", 50 | "extract-text-webpack-plugin": "^3.0.0", 51 | "file-loader": "^1.1.4", 52 | "friendly-errors-webpack-plugin": "^1.6.1", 53 | "html-webpack-plugin": "^2.30.1", 54 | "http-proxy-middleware": "^0.17.3", 55 | "opn": "^5.1.0", 56 | "optimize-css-assets-webpack-plugin": "^3.2.0", 57 | "ora": "^1.2.0", 58 | "portfinder": "^1.0.13", 59 | "rimraf": "^2.6.0", 60 | "semver": "^5.3.0", 61 | "shelljs": "^0.7.6", 62 | "url-loader": "^0.5.8", 63 | "vue-loader": "^13.0.4", 64 | "vue-style-loader": "^3.0.1", 65 | "vue-template-compiler": "^2.4.2", 66 | "webpack": "^3.6.0", 67 | "webpack-bundle-analyzer": "^2.9.0", 68 | "webpack-dev-middleware": "^1.12.0", 69 | "webpack-hot-middleware": "^2.18.2", 70 | "webpack-merge": "^4.1.0" 71 | }, 72 | "engines": { 73 | "node": ">= 4.0.0", 74 | "npm": ">= 3.0.0" 75 | }, 76 | "browserslist": [ 77 | "> 1%", 78 | "last 2 versions", 79 | "not ie <= 8" 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /webui/src/App.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 67 | 68 | 72 | -------------------------------------------------------------------------------- /webui/src/Bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default new Vue({ 4 | data () { 5 | return { 6 | curSourceFile: '' 7 | } 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /webui/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/webui/src/assets/logo.png -------------------------------------------------------------------------------- /webui/src/components/BreakpointNav.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 77 | 78 | 82 | -------------------------------------------------------------------------------- /webui/src/components/FileNav.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 60 | 61 | 65 | -------------------------------------------------------------------------------- /webui/src/components/FuncNav.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 77 | 78 | 82 | -------------------------------------------------------------------------------- /webui/src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 54 | 55 | 61 | 62 | 67 | -------------------------------------------------------------------------------- /webui/src/components/Index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | 29 | 35 | -------------------------------------------------------------------------------- /webui/src/components/PopupList.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 109 | -------------------------------------------------------------------------------- /webui/src/components/Source.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 366 | 367 | 377 | 378 | 382 | -------------------------------------------------------------------------------- /webui/src/components/TracesNav.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 69 | 70 | 77 | -------------------------------------------------------------------------------- /webui/src/components/wiki/WikiEn.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 129 | 130 | 134 | -------------------------------------------------------------------------------- /webui/src/components/wiki/WikiZh.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 132 | 133 | 137 | -------------------------------------------------------------------------------- /webui/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | import Axios from 'axios' 7 | import BootstrapVue from 'bootstrap-vue' 8 | import Bus from './Bus.js' 9 | import VueLocalStorage from 'vue-localstorage' 10 | import VueMarkdown from 'vue-markdown' 11 | 12 | import 'bootstrap/dist/css/bootstrap.css' 13 | import 'bootstrap-vue/dist/bootstrap-vue.css' 14 | 15 | import 'vue-awesome/icons/close' 16 | import Icon from 'vue-awesome/components/Icon' 17 | 18 | Vue.component('icon', Icon) 19 | Vue.component('VueMarkdown', VueMarkdown) 20 | 21 | Vue.use(VueLocalStorage) 22 | 23 | Vue.use(BootstrapVue) 24 | 25 | Vue.prototype.$http = Axios 26 | 27 | Vue.prototype.$bus = Bus 28 | 29 | Vue.config.productionTip = false 30 | 31 | /* eslint-disable no-new */ 32 | new Vue({ 33 | el: '#app', 34 | router, 35 | template: '', 36 | components: { App } 37 | }) 38 | -------------------------------------------------------------------------------- /webui/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Source from '@/components/Source' 4 | import Index from '@/components/Index' 5 | import Home from '@/components/Home' 6 | 7 | Vue.use(Router) 8 | 9 | export default new Router({ 10 | routes: [ 11 | { 12 | path: '/trace/source/:id', 13 | name: 'Source', 14 | component: Source 15 | }, 16 | { 17 | path: '/home', 18 | name: 'Home', 19 | component: Home 20 | }, 21 | { 22 | path: '/', 23 | name: 'Index', 24 | component: Index 25 | } 26 | ] 27 | }) 28 | -------------------------------------------------------------------------------- /webui/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxikun/ytrace_gui/052d77b32e698d8d4adba94ef6c66f8489eb2854/webui/static/.gitkeep --------------------------------------------------------------------------------